UDF
UDF
UDF
September 2000
Licensee acknowledges that use of Fluent Inc.'s products can only provide an imprecise
estimation of possible future performance and that additional testing and analysis, independent of the Licensor's products, must be conducted before any product can be nally
developed or commercially introduced. As a result, Licensee agrees that it will not rely
upon the results of any usage of Fluent Inc.'s products in determining the nal design,
composition or structure of any product.
and Company. All other products or name brands are trademarks of their respective
holders.
Fluent Inc.
Centerra Resource Park
10 Cavendish Court
Lebanon, NH 03766
ii
Contents
1 Overview
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . .
UDF Format . . . . . . . . . . . . . . . . . . . . . . . . . .
Including the udf.h File . . . . . . . . . . . . . . . . . . . .
Dening Your Function . . . . . . . . . . . . . . . . . . . .
2.4.1 Introduction . . . . . . . . . . . . . . . . . . . . . .
2.4.2 #define Statements in the udf.h File . . . . . . . .
2.4.3 DEFINE Macros . . . . . . . . . . . . . . . . . . . . .
2.5 General-Use DEFINE Macros and the Functions They Dene
2.5.1 DEFINE ADJUST . . . . . . . . . . . . . . . . . . . . .
2.5.2 DEFINE DIFFUSIVITY . . . . . . . . . . . . . . . . .
2.5.3 DEFINE HEAT FLUX . . . . . . . . . . . . . . . . . . .
2.5.4 DEFINE INIT . . . . . . . . . . . . . . . . . . . . . .
2.5.5 DEFINE ON DEMAND . . . . . . . . . . . . . . . . . . .
2.5.6 DEFINE PROFILE . . . . . . . . . . . . . . . . . . . .
2.5.7 DEFINE PROPERTY . . . . . . . . . . . . . . . . . . .
2.5.8 DEFINE RW FILE . . . . . . . . . . . . . . . . . . . .
2.5.9 DEFINE SCAT PHASE FUNC . . . . . . . . . . . . . . .
2.5.10 DEFINE SOURCE . . . . . . . . . . . . . . . . . . . . .
2.5.11 DEFINE SR RATE . . . . . . . . . . . . . . . . . . . .
2.5.12 DEFINE UDS FLUX . . . . . . . . . . . . . . . . . . .
2.5.13 DEFINE UDS UNSTEADY . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
3
5
5
6
6
6
7
8
10
10
10
11
11
12
12
12
13
13
13
14
14
14
CONTENTS
2.6
2.7
2.8
2.9
2.10
iv
2.5.14
...........................
DEFINE Macros for the Discrete Phase Model and the Functions They Dene
2.6.1 DEFINE DPM BODY FORCE . . . . . . . . . . . . . . . . . . . . . . .
2.6.2 DEFINE DPM DRAG . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.3 DEFINE DPM EROSION . . . . . . . . . . . . . . . . . . . . . . . .
2.6.4 DEFINE DPM INJECTION INIT . . . . . . . . . . . . . . . . . . . .
2.6.5 DEFINE DPM LAW . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.6 DEFINE DPM OUTPUT . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.7 DEFINE DPM PROPERTY . . . . . . . . . . . . . . . . . . . . . . . .
2.6.8 DEFINE DPM SCALAR UPDATE . . . . . . . . . . . . . . . . . . . . .
2.6.9 DEFINE DPM SOURCE . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.10 DEFINE DPM SWITCH . . . . . . . . . . . . . . . . . . . . . . . . .
DEFINE Macros for Multiphase Models and the Functions They Dene .
2.7.1 DEFINE DRIFT DIAM . . . . . . . . . . . . . . . . . . . . . . . . .
2.7.2 DEFINE SLIP VELOCITY . . . . . . . . . . . . . . . . . . . . . . .
Determining the Pointer to a Thread . . . . . . . . . . . . . . . . . . . .
Function Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9.2 Restrictions on Interpreted UDFs . . . . . . . . . . . . . . . . .
2.9.3 Function Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9.4 Returning a Value . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9.5 Modifying an Argument . . . . . . . . . . . . . . . . . . . . . . .
2.9.6 Returning a Value and Modifying an Argument . . . . . . . . . .
2.9.7 Modifying a FLUENT Variable . . . . . . . . . . . . . . . . . . .
2.9.8 Writing to or Reading from a Case or Data File . . . . . . . . . .
Solver Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.10.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.10.2 Miscellaneous Geometry . . . . . . . . . . . . . . . . . . . . . . .
2.10.3 Cell Coordinates and Areas . . . . . . . . . . . . . . . . . . . . .
2.10.4 Node Coordinates and Node (Grid) Velocities . . . . . . . . . . .
DEFINE VR RATE
15
16
16
16
17
17
17
18
18
19
19
20
21
21
21
22
23
23
23
24
25
26
27
28
29
31
31
32
32
33
CONTENTS
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
33
34
36
37
37
38
38
39
41
57
3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2 Interpreted UDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.2.1 Compiling an Interpreted UDF . . . . . . . . . . . . . . . . . . . 43
3.2.2 Directory Structure for Windows NT Parallel Networks . . . . . 45
3.2.3 Debugging Interpreted UDFs . . . . . . . . . . . . . . . . . . . . 46
3.2.4 Common Errors Made While Compiling Your Interpreted UDF . 46
3.3 Compiled UDFs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.3.1 Setting Up the Directory Structure . . . . . . . . . . . . . . . . . 48
3.3.2 Compiling and Building Your Shared Library . . . . . . . . . . . 52
3.3.3 Linking Your Shared Library to the FLUENT Executable . . . . . 55
3.3.4 Common Errors Made While Compiling or Linking Your Compiled
UDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
4.1
4.2
4.3
4.4
4.5
4.6
4.7
Boundary Conditions . . . . . . .
Source Terms . . . . . . . . . . .
Property Denitions . . . . . . .
Discrete Phase Model . . . . . .
Solution Initialization . . . . . .
Adjustment of Computed Values
Wall Heat Fluxes . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
58
59
60
62
63
63
64
v
CONTENTS
4.8
4.9
4.10
4.11
4.12
4.13
Reaction Rates . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Slip Velocity for the Algebraic Slip Mixture Model . . . . . . . . .
Particle or Droplet Diameter for the Algebraic Slip Mixture Model
Reading from and Writing to Case and Data Files . . . . . . . . . .
Executing a UDF On Demand . . . . . . . . . . . . . . . . . . . .
Accessing Memory for Storage of Variables . . . . . . . . . . . . . .
5 Examples of UDFs
6 Sample Applications
vi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
64
64
65
66
66
67
69
70
70
72
76
77
77
79
81
85
85
88
89
90
91
92
95
97
97
97
103
109
109
CONTENTS
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
114
114
118
118
123
B C Library Functions
125
vii
CONTENTS
viii
Chapter 1. Overview
User-dened functions (UDFs) are functions that you can write to enhance the standard
features of FLUENT. UDFs are written in the C programming language and have two
dierent modes of execution: interpreted and compiled. Interpreted UDFs are simpler to
use but have coding and speed limitations. Compiled UDFs execute much more quickly
and have no coding limitations, but require more eort to set up and use.
You can use UDFs to customize:
boundary conditions
source terms
property denitions (except specic heat)
surface and volume reaction rates
user-dened scalar transport equations
discrete phase model (e.g., body force, drag, source terms)
algebraic slip mixture model (slip velocity and particle size)
solution initialization
wall heat
uxes
postprocessing using user-dened scalars
Boundary condition UDFs can be used to generate proles as a function of time, distance, and
ow-eld value. For example, you may want to specify an x-velocity boundary
condition as a function of
ow time, or you may want to specify a temperature boundary
condition as a function of position. Boundary condition prole UDFs are dened using
the DEFINE PROFILE macro. Examples of boundary condition UDFs are provided in Section 5.1. Sample applications of boundary condition UDFs are presented in Section 6.1.
Source term UDFs can be used to modify source terms in any of the transport equations except for the DO radiation model. Source term UDFs are dened using the
DEFINE SOURCE macro. Examples of UDFs that modify source terms are provided in
Section 5.2. See Section 6.2 for an application of a source term UDF.
Property UDFs can be used to specify custom physical properties, except for specic heat.
For example, you may want to specify viscosity as a function of temperature. Property
Overview
UDFs are dened using the DEFINE PROPERTY macro. An application of a property UDF
in FLUENT is presented in Section 6.3.
Reaction rate UDFs can be used to generate custom surface or volume reaction rates.
These UDFs are dened using the DEFINE SR RATE and DEFINE VR RATE macros, respectively. See Section 6.4 for a sample application.
You can also use UDFs to specify custom parameters for the discrete phase model. UDFs
for the discrete phase model are dened using DEFINE DPM macros. See Section 5.4 for
examples of UDFs that are specic to the discrete phase model.
UDFs can also be written to customize a user-dened scalar transport equation, initialize
a solution, specify a wall heat
ux, or compute and store a value of a variable (using userdened scalars or user-dened memory) that can subsequently be used for postprocessing.
Examples of UDFs for each type of application can be found in the following sections:
Section 5.3 (user-dened scalar transport equations); Section 5.5 (solution initialization);
Section 5.6 (wall heat
ux); and Section 5.7 (postprocessing using user-dened scalars).
Although the UDF capability in FLUENT 5 can address a wide range of applications, it
is not possible to address every application in the present document. If you are unsure
whether a particular problem can be handled using a UDF, you can contact your technical
support engineer for assistance.
1.1 Basic Steps for Writing UDFs
There are ve basic steps that typically occur during the process of writing UDFs and
using them eectively in your FLUENT model:
are architecture-independent.
can all be run as compiled UDFs.
cannot be linked to compiled system or user libraries.
are less powerful than compiled UDFs due to limitations in the C language
supported by the interpreter. In particular, interpreted UDFs cannot contain:
goto statements
non ANSI-C prototypes for syntax
declarations of local structures, unions, pointers to functions, and arrays
of functions
direct structure references
Interpreted UDFs can indirectly access data stored in a FLUENT structure
if the data are accessed using one of the Fluent-provided macros listed in
Section 2.10.
Overview
Compiled UDFs
{
{
{
{
{
In summary, when deciding which type of UDF to use for your FLUENT model:
Use interpreted UDFs for small, straightforward functions.
Use compiled UDFs for complex functions that
{
{
{
have a signicant CPU requirement (e.g., a property UDF that is called on a
per-cell basis every iteration).
require access to a compiled library.
require access to a variable for which there is not a Fluent-provided macro.
macro replacement-text
Before compilation, the C preprocessor (e.g., cpp) performs a macro substitution using
the #define information provided in the udf.h le. For every #define statement included in your UDF by the #include "udf.h" statement, the preprocessor performs a
simple substitution and expands the occurrence of each argument in macro using the
replacement-text.
For example, the macro
DEFINE_PROFILE(inlet_x_velocity, thread, position)
expands to
void inlet_x_velocity(Thread *thread, int position)
The function that is named in the DEFINE macro will either return a value of a particular
data type (e.g., real), or not return any value if the name argument in the DEFINE macro
is dened as void. For example, the function inlet x velocity does not return a
value since it is declared as a void data type. The function that is named in any
DEFINE PROPERTY macro, for example, returns a real value since it is declared as a real
data type in the udf.h le.
2.4.3
Macros
DEFINE macros are used to dene UDFs. They are divided into three categories: general
use, discrete phase, and multiphase DEFINE macros, which are listed below. Each macro
begins with the prex DEFINE (all caps). You can get a general idea of what a particular
function (that is dened by a macro) does by looking at the part of the name following the
DEFINE prex. For example, the DEFINE SOURCE macro denes a function that modies
source terms, while DEFINE PROPERTY is used to dene a function that allows you to
customize a material property.
Descriptions of functions that are dened using general-use DEFINE macros are presented
in Section 2.5. Functions for the discrete phase model macros are described in Section 2.6,
and functions for multiphase models are described in Section 2.7. In addition to a description, each function's arguments, argument types, and return type are provided in
a table for easy reference. Refer to Appendix A for DEFINE macro denitions (from the
udf.h le).
DEFINE
DEFINE ADJUST
DEFINE DIFFUSIVITY
DEFINE HEAT FLUX
DEFINE INIT
DEFINE ON DEMAND
DEFINE PROFILE
DEFINE PROPERTY
DEFINE RW FILE
DEFINE SCAT PHASE FUNC
DEFINE SOURCE
DEFINE SR RATE
DEFINE UDS FLUX
DEFINE UDS UNSTEADY
DEFINE VR RATE
DEFINE ADJUST
Name
Domain *domain
void
A DEFINE ADJUST function is called at the beginning of every iteration, just before solving
the transport equations. It can be used to modify
ow variables, compute integrals, etc.
The Domain pointer argument domain is passed to the function by the solver to give
access to all the cell and face threads in the domain. The function does not return a
value.
See Section 4.6 for information about activating the function within FLUENT. Examples
of UDFs that are dened using the DEFINE ADJUST macro can be found in Sections 5.3,
5.6, and 5.7.
2.5.2
DEFINE DIFFUSIVITY
Name
Arguments Argument Type
DEFINE DIFFUSIVITY c, t, i
Return Type
A DEFINE DIFFUSIVITY function is used to specify the diusivity for the species equations
or user-dened scalar equations. The argument c is the index of the cell, Thread pointer
t points to the thread of the cell, and i is the index of the species or user-dened scalar
(with its value passed to the UDF by the solver). The function returns the real value
of diusivity.
An example of a UDF that is dened using the DEFINE DIFFUSIVITY macro can be found
in Section 5.3.
10
2.5.3
Name
Return Type
A DEFINE HEAT FLUX function allows you to customize how diusive and radiative heat
uxes between a cell and a neighboring wall are to be computed in the energy equation.
You can use this DEFINE macro to specify one or both types of heat
uxes. The argument
f is the index of the wall face, Thread pointer t points to the thread of the wall face, c0
is the index of the cell next to the wall, and Thread pointer t0 points to the thread of the
cell. Your UDF needs to specify the diusive heat
ux coecient (cid), and the radiative
heat
ux coecient (cir). With these inputs, diusive heat
ux (qid) and radiative heat
ux (qir), respectively, will then be computed by FLUENT using the following equations:
qid = cid[0] + cid[1]*C_T(c0,t0) - cid[2]*F_T(f,t) - cid[3]*pow(F_T(f,t),4)
qir = cir[0] + cir[1]*C_T(c0,t0) - cir[2]*F_T(f,t) - cir[3]*pow(F_T(f,t),4)
DEFINE INIT
Name
Domain *domain
void
Customized initialization functions can be implemented with the DEFINE INIT macro.
Note that this function will be called after the default initialization is performed. The
Domain pointer argument domain is passed into the function by the solver to give access
to all the cell and face threads. The function does not return a value.
See Section 4.5 for information about selecting the function within FLUENT. Examples
of UDFs that are dened using the DEFINE INIT macro can be found in Sections 5.4.1
and 5.5.
11
2.5.5
DEFINE ON DEMAND
Name
Arguments Argument Type Return Type
DEFINE ON DEMAND
void
A DEFINE ON DEMAND macro is used to dene a UDF that you want to execute on demand
in FLUENT, rather than having FLUENT call it automatically during the calculation.
See Section 4.12 for information about selecting and executing the function within FLUENT. An example of a UDF that is dened using the DEFINE ON DEMAND macro can be
found in Section 5.8.
2.5.6
DEFINE PROFILE
Name
Arguments Argument Type Return Type
DEFINE PROFILE t, i
void
A DEFINE PROFILE function is used to specify prole boundary conditions (i.e., boundary
conditions varying as functions of spatial coordinates or time). Arguments are Thread
pointer t, which points to the thread on which the boundary condition is to be applied,
and i, which is the index of the location where the boundary condition is to be stored
(with its value passed to the UDF by the solver). The function should loop over all the
faces in the boundary thread, and the boundary condition for faces on a thread is stored
in F PROFILE(f,t,i) for all faces with index f that are on the thread pointed to by t.
The function does not return a value.
See Section 4.1 for information about selecting the function within FLUENT. Examples of
UDFs that are dened using the DEFINE PROFILE macro can be found in Sections 5.1.1,
5.1.2, 5.1.3, 5.3, 6.1.1, and 6.1.2.
2.5.7
DEFINE PROPERTY
Name
Arguments Argument Type
DEFINE PROPERTY c, t
Return Type
12
2.5.8
DEFINE RW FILE
Name
Arguments Argument Type Return Type
DEFINE RW FILE fp
FILE *fp
void
real c, real *f
real
A DEFINE SCAT PHASE FUNC function can be used to dene the radiation scattering phase
function for the discrete ordinates model. This function computes two values: the fraction
of radiation energy scattered from direction i to direction j , and the forward scattering
factor. The real variable c is the cosine of the angle between the two directions. The
fraction of radiation energy scattered from direction i to direction j is returned by the
function, and the forward scattering factor is stored in the real variable that is referenced
by the real pointer f. The solver computes and stores a scattering matrix for each
material by calling this function for each unique pair of discrete ordinates.
2.5.10
DEFINE SOURCE
Name
Arguments Argument Type
DEFINE SOURCE c, t,
dS, i
Return Type
A DEFINE SOURCE function is used to specify source terms for any of the solved transport
equations except for the DO radiation model. The function typically loops over cells in
a cell thread and computes the source term. The argument c is the index of the cell,
and Thread pointer t points to the thread of the cell. Array dS is used to specify the
derivatives of the source with respect to the coupled equations (i.e., equations that are
coupled together for solution). These derivatives are used in linearizing the source term
to enhance the stability of the solver. The index i is the index of the equation for which
the source is being specied (with its value passed to the UDF by the solver). Note that if
the source is being specied for an equation that is not coupled with any other equation,
c
13
then only the derivative with respect to the solved variable needs to be specied (i.e.,
only dS[i]). The function returns the value of the source term.
See Section 4.2 for information about selecting the function within FLUENT. Examples
of UDFs that are dened using the DEFINE SOURCE macro can be found in Sections 5.2.1,
5.2.2, 5.3, and 6.2.1.
2.5.11
DEFINE SR RATE
Name
Arguments Argument Type
DEFINE SR RATE f, t,
r, mw,
yi, rr
Return Type
A DEFINE SR RATE function can be used to customize a surface reaction rate. Here f
is the index of the face, Thread pointer t points to the thread of the face, Reaction
pointer r points to the reaction structure, mw is a pointer to a real array containing
the species molecular weights, and yi is a pointer to a real array containing the species
mass fractions. The value referenced by the real pointer rr is to be set in the function.
The function does not return a value.
See Section 4.8 for information about activating the function within FLUENT.
2.5.12
Return Type
A DEFINE UDS FLUX function is used to specify how the convective
ux is to be computed
for the user-dened scalar transport equations. Here f is the index of the face on which
the
ux is required, Thread pointer t points to the thread of the face, and i is the index
of the user-dened scalar (with its value passed to the UDF by the solver).
2.5.13
Name
Return Type
A DEFINE UDS UNSTEADY function is used to specify unsteady terms for a user-dened
scalar transport equation. Here c is the index of the cell, Thread pointer t points to the
14
thread of the cell, and i is the index of the user-dened scalar (with its value passed to
the UDF by the solver).
In FLUENT, the unsteady term is moved to the RHS and discretized as follows:
unsteady term =
@
() dV
" @t n
() ()n 1 # V
t
V n V n 1
+
|
{zt }
| t {z }
apu
(2.5-1)
su
and su are the parts of the unsteady term corresponding to the central coecient
and the source term, respectively.
This function does not return a value.
apu
2.5.14
DEFINE VR RATE
Name
Arguments Argument Type
DEFINE VR RATE c, t,
r, mw,
yi, rr, rr t
Return Type
A DEFINE VR RATE function can be used to customize a volume reaction rate. Here c
is the index of the cell, Thread pointer t points to the thread of the cell, Reaction
pointer r points to the reaction structure, mw is a real pointer array of the species
molecular weights, and yi is a real pointer array of the species mass fractions. The
values referenced by the real pointers rr and rr t are to be set to the laminar and
turbulent reaction rates in the function. The function does not return a value.
See Section 4.8 for information about activating the function within FLUENT. An example
of a UDF that is dened using the DEFINE VR RATE macro can be found in Section 6.4.1.
15
2.6
2.6.1
Name
Return Type
A DEFINE DPM BODY FORCE function can be used to specify a body force on the particle other than a gravitational or drag force. The argument p is a pointer to the
Tracked Particle being tracked, and i is the index (0, 1, or 2, with its value passed to
the UDF by the solver) for the Cartesian component of the force to be returned. The
returned value is an acceleration.
See Section 4.4 for information about activating the function within FLUENT. An example of a UDF that is dened using the DEFINE DPM BODY FORCE macro can be found in
Section 5.4.2.
2.6.2
Return Type
A DEFINE DPM DRAG function can be used to specify the drag coecient, CD , dened by
the following equation:
FD =
18 CD Re
p Dp2 24
The argument Re is the particle Reynolds number based on the particle diameter and
relative gas velocity, and p is a pointer to the Tracked Particle being tracked. The
value returned will be dimensionless and represent 18 * Cd * Re / 24.
See Section 4.4 for information about activating the function within FLUENT. An example
of a UDF that is dened using the DEFINE DPM DRAG macro can be found in Section 5.4.3.
16
2.6 DEFINE Macros for the Discrete Phase Model and the Functions They Dene
2.6.3
Name
Arguments
Argument Type
Return Type
A DEFINE DPM EROSION function allows access to the erosion and accretion rates calculated as the particle stream strikes a wall surface. The arguments for the function are
the pointer p to the Tracked Particle being tracked; the pointer t to the Thread of
the face the particle is hitting; the index f of the face the particle is hitting; the array normal, which contains the unit vector normal to the face; the impact angle alpha
between the particle path and the face (in radians); the magnitude of the particle velocity Vmag; and the
ow rate mdot of the particle stream as it hits the face. The
calculated values for the erosion rate and/or accretion rate will be stored at the faces in
F STORAGE R(f,t,SV DPMS EROSION) and F STORAGE R(f,t,SV DPMS ACCRETION). The
function does not return a value.
See Section 4.4 for information about activating the function within FLUENT.
2.6.4
Injection *I
void
A DEFINE DPM INJECTION INIT function can be used to specify particle properties at the
time of injection. The argument I is a pointer to the Injection for which the particles
are being created. This function is called twice for each Injection before the rst DPM
iteration, and then called once for each Injection before the particles are injected into
the domain at each subsequent DPM iteration. Initial particle properties such as location,
diameter, and velocity can be modied. The function does not return a value.
2.6.5
Return Type
A DEFINE DPM LAW function can be used to specify the heat and mass transfer rates for
droplets and combusting particles. The arguments are the pointer p to the Tracked Particle
currently being tracked; and the integer ci, which indicates if the continuous and discrete
c
17
phases are coupled (equal to 1 if coupled, otherwise 0). The particle's properties (mass,
diameter, temperature, etc.) are modied as the droplet or particle exchanges mass and
energy with its surroundings. The function does not return a value.
2.6.6
Name
Return Type
A DEFINE DPM OUTPUT function allows access to the variables that are written as a particle
passes through a sample plane (see Section 14.10.6 in the FLUENT 5 User's Guide). The
arguments are header, which is set to 1 at the rst call of the function before particles
are tracked and set to 0 for subsequent calls; the le index fp to which the information
is being written; the pointer p to the Tracked Particle being tracked; the pointer t to
the Thread the particle is passing through if it is a grid surface (otherwise t is NULL);
and the pointer plane to the Plane structure (dpm.h) if the particle is passing through a
planar (line in 2D) slice (plane is NULL if the particle is passing through a grid surface).
The output will be written to the le indicated by fp. The function does not return a
value.
An example of a UDF that is dened using the DEFINE DPM OUTPUT macro can be found
in Section 5.4.1.
2.6.7
Return Type
A DEFINE DPM PROPERTY function is used for specifying properties of discrete phase materials. It has the same arguments as the DEFINE PROPERTY function (described in Section 2.5.7), with the addition of the pointer to the Tracked Particle p. The argument
c is the index of the cell, and Thread pointer t points to the thread of the cell. The
function returns the value of the discrete phase property.
18
2.6 DEFINE Macros for the Discrete Phase Model and the Functions They Dene
2.6.8
Return Type
Return Type
A DEFINE DPM SOURCE function allows access to the accumulated source terms for a particle in a given cell before they are added to the mass, momentum, and energy exchange
terms for coupled DPM calculations. The arguments are c, the cell index cell t that the
particle is currently in; t, the cell Thread that the particle is currently in; S, the pointer
to the source structure dpms t which contains the source terms for the cell; strength, the
particle number
ow rate in particles/second (divided by the number of tries if stochastic tracking is used); and p, the pointer to the Tracked Particle being tracked. The
modied source terms will be stored in S. The function does not return a value.
See Section 4.4 for information about activating the function within FLUENT.
19
2.6.10
Return Type
The DEFINE DPM SWITCH function can be used to control the switching between the userdened particle laws and the default particle laws, or between dierent user-dened or
default particle laws. The arguments are the pointer p to the Tracked Particle currently
being tracked; and the integer ci, which indicates if the continuous and discrete phases
are coupled (equal to 1 if coupled, otherwise 0). The function does not return a value.
20
2.7 DEFINE Macros for Multiphase Models and the Functions They Dene
2.7
2.7.1
Return Type
A DEFINE DRIFT DIAM function can be used to dene the particle or droplet diameter for
the algebraic slip mixture model. The argument c is the index of the cell, and Thread
pointer t points to the thread of the cell. The function returns the value of the particle
or droplet diameter.
See Section 4.10 for information about selecting the function within FLUENT.
2.7.2
Domain *domain
void
A DEFINE SLIP VELOCITY function can be used to dene the slip velocity for the algebraic
slip mixture model. The Domain pointer argument domain is passed into the function by
the solver to give access to all the cell and face threads. The function does not return a
value.
See Section 4.9 for information about selecting the function within FLUENT.
21
DEFINE_ON_DEMAND(get_coords)
{
fout = fopen("faces.out", "w");
Print_Thread_Face_Centroids(domain, 2);
Print_Thread_Face_Centroids(domain, 4);
fclose(fout);
}
22
return mu_lam;
tions.
direct structure references
All data stored in a FLUENT structure must be accessed using one of the Fluentprovided macros listed in Section 2.10.
23
Return a value
Modify an argument
Return a value and modify an argument
Modify a FLUENT variable (not passed as an argument)
Write information to (or read information from) a case or data le
Functions that are dened with a DEFINE macro return a value unless they are dened
as void in the udf.h le (see #define statements for the DEFINE macros in the udf.h
le). If they do not return a value, they may either modify an argument, or modify a
variable stored in memory.
Examples of UDFs that perform each of the ve function tasks are presented in the
following sections.
24
return mu_lam;
The function cell viscosity is dened using the DEFINE PROPERTY macro (described in
Section 2.5.7). Two real variables are introduced: mu lam, the laminar viscosity computed
by the function; and temp, the value of C T(cell,thread) which is the temperature value
in the cell under consideration. The value of the temperature is checked, and based upon
the range into which it falls, the appropriate value of mu lam is computed. At the end
of the function, the computed value for mu lam is returned. See Section 6.3.1 for more
details about this UDF.
25
A function named user rate is dened using the DEFINE VR RATE macro (described in
Section 2.5.14). The UDF performs a test if the current cell under consideration is in
a porous region, and only applies the reaction rate equation in porous regions. The
real pointer variable rate is an argument passed to the function. The UDF assigns the
value of the reaction rate to the dereferenced pointer *rate. By using the dereferencing
operator *, the object that the pointer rate points to is set to the reaction rate (see
Kernighan and Ritchie's \The C Programming Language", Prentice Hall, 1988 for more
details on dereferencing). In this way, the word that is stored in memory at the pointer
address is changed, and not the pointer address itself. See Section 6.4.1 for more details
about this UDF.
26
return source;
In this UDF, a function named user swirl is dened using the DEFINE SOURCE macro
(described in Section 2.5.10). The function species a source term for swirl velocity. It
takes the argument dS, and modies it by setting it equal to the derivative of the source
term. The function also computes the value of the source term, source, and returns this
value to the solver. See Section 5.2.2 for more details about this UDF.
27
begin_f_loop(f, thread)
{
F_CENTROID(x,f,thread);
y = x[1];
F_PROFILE(f, thread, position) = 20. - y*y/(.0745*.0745)*20.;
}
end_f_loop(f, thread)
In this UDF, a function named inlet x velocity is dened using the DEFINE PROFILE
macro (described in Section 2.5.6). Its arguments are thread and position. thread is
a pointer to the face's thread, and position is an integer that is a numerical label for
the variable being set within each loop.
The function begins by declaring variable f as a face t data type. A one-dimensional
array x and variable y are real data types. A looping macro is then used to loop over each
face in the zone to create a prole, or an array of data. Within each loop, F CENTROID
outputs the value of the face centroid (array x) for the face with index f that is on the
thread pointed to by thread. The y coordinate stored in x[1] is assigned to variable y,
which is then used to calculate the x velocity. This value is then assigned to F PROFILE,
which uses the integer position (passed to it by the solver) to set the x-velocity value
in memory at the face.
28
DEFINE_ADJUST(demo_calc, domain)
{
kount++;
printf("kount = %d\n",kount);
}
DEFINE_RW_FILE(writer, fp)
{
printf("Writing UDF data to data file...\n");
fprintf(fp, "%d",kount); /* write out kount to data file */
}
DEFINE_RW_FILE(reader, fp)
{
printf("Reading UDF data from data file...\n");
fscanf(fp, "%d",&kount); /* read kount from data file */
}
At the top of the listing, the integer kount is dened and initialized to zero. The rst
function (demo calc) is an ADJUST function that increments the value of kount at each
iteration, since the ADJUST function is called once per iteration. (See Section 2.5.1 for
more information about ADJUST functions.) The second function (writer) instructs
c
29
to write the current value of kount to the data le, when the data le is
saved. The third function (reader) instructs FLUENT to read the value of kount from
the data le, when the data le is read.
The functions work together as follows. If, for example, you run your calculation for 10
iterations (hence kount has been incremented to a value of 10) and save the data le,
the current value of kount (10) will be written to your data le. If you read the data
back into FLUENT and continue the calculation, kount will start at a value of 10 and be
incremented from there at each iteration.
Note that you can save as many static variables as you want, but you must be sure to
read them in the same order that they are written.
FLUENT
30
quantities)
cell and face metrics (e.g., face area, cell volume, cell center coordinates)
properties (e.g., density, viscosity, conductivity)
! Note that you can access specic heat data, but you cannot modify it.
You can access solver data in your UDF by using Fluent-provided functions that are listed
in the following sections. The word \function" is used loosely here, since these functions
are implemented in FLUENT as functions or macros. To obtain a precise denition for a
particular \function" described below, refer to the appropriate .h source le.
! Note that if you are writing a UDF that will be executed as an interpreted UDF, you
can access solver data only using a Fluent-provided function.
Solver functions can be used in the body of your C code, along with C library functions,
to specify your UDF. For your convenience, a list of commonly-used C library functions
is provided in Appendix B.
Each of the Fluent-provided functions in the following sections is listed with its arguments, argument types, returned value, and name of the source le that contains the
denition statements. Arguments are either inputs to the function, or outputs.
For example, the function
C_CENTROID(x,c,t)
has three arguments: x, c, and t. In this case, c and t are input arguments, while the
variable x[ND ND] (the cell centroid) is output to the solver.
31
cell t c, Thread *t
cell t c, Thread *t
face t f, Thread *t
Returns
Source
32
Returns
Source
C CENTROID(x,c,t)
F CENTROID(x,f,t)
x (cell centroid)
x (face centroid)
metric.h
metric.h
F AREA(A,f,t)
NV MAG(A)
A (area vector)
metric.h
metric.h
C VOLUME(c,t)
cell t c, Thread *t
cell volume
mem.h
for 2D or 3D,
cell volume/2
for axisymmetric
area magnitude
X(node)
Y(node)
Z(node)
GX(node)
GY(node)
GZ(node)
Node
Node
Node
Node
Node
Node
x coordinate of node
y coordinate of node
z coordinate of node
x component of node velocity
y component of node velocity
z component of node velocity
*node
*node
*node
*node
*node
*node
Source
metric.h
metric.h
metric.h
mem.h
mem.h
mem.h
P(f,t)
U(f,t)
V(f,t)
W(f,t)
T(f,t)
H(f,t)
K(f t)
D(f,t)
F YI(f,t,i)
F UDSI(f,t,i)
F UDMI(f,t,i)
Source
pressure
mem.h (all)
u velocity
v velocity
w velocity
temperature
enthalpy
turbulent kinetic energy
turbulent energy
dissipation
face t f, Thread *t, int i species mass fraction
face t f, Thread *t, int i user-dened scalar
face t f, Thread *t, int i user-dened memory
face
face
face
face
face
face
face
face
t
t
t
t
t
t
t
t
f,
f,
f,
f,
f,
f,
f,
f,
Returns
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
*t,
*t,
*t,
*t,
*t,
*t,
*t,
*t,
33
Argument Types
C
C
C
C
C
C
C
C
C
C
C
P(c,t)
U(c,t)
V(c,t)
W(c,t)
T(c,t)
H(c,t)
YI(c,t,i)
UDSI(c,t,i)
UDMI(c,t,i)
K(c,t)
D(c,t)
cell
cell
cell
cell
cell
cell
cell
cell
cell
cell
cell
t
t
t
t
t
t
t
t
t
t
t
C
C
C
C
C
C
C
RUU(c,t)
RVV(c,t)
RWW(c,t)
RUV(c,t)
RVW(c,t)
RUW(c,t)
FMEAN(c,t)
cell
cell
cell
cell
cell
cell
cell
t
t
t
t
t
t
t
C FMEAN2(c,t)
cell t
C FVAR(c,t)
cell t
C FVAR2(c,t)
cell t
C PREMIXC(c,t)
cell t
C
C
C
C
cell
cell
cell
cell
C VOF(c,t,1)
34
t
t
t
t
cell t
c,
c,
c,
c,
c,
c,
c,
c,
c,
c,
c,
Returns
Source
pressure
mem.h
u velocity
v velocity
w velocity
temperature
enthalpy
species mass fraction
user-dened scalar
user-dened memory
turb. kinetic energy
turbulent energy
dissipation
c, Thread *t
uu Reynolds stress
sg mem.h
c, Thread *t
vv Reynolds stress
c, Thread *t
ww Reynolds stress
c, Thread *t
uv Reynolds stress
c, Thread *t
vw Reynolds stress
c, Thread *t
uw Reynolds stress
c, Thread *t
primary mean
mixture fraction
c, Thread *t
secondary mean
mixture fraction
c, Thread *t
primary mixture
fraction variance
c, Thread *t
secondary mixture
fraction variance
c, Thread *t
reaction progress
variable
c, Thread *t
laminar
ame speed
c, Thread *t
critical strain rate
c, Thread *t, int i pollutant species
c, Thread *t
volume fraction for
primary phase
c, Thread *t
volume fraction for
secondary phase
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
*t
*t
*t
*t
*t
*t
*t, int i
*t, int i
*t, int i
*t
*t
Derivatives
Name(Arguments)
Argument Types
C
C
C
C
C
C
C
C
C
C
C
cell
cell
cell
cell
cell
cell
cell
cell
cell
cell
cell
DUDX(c,t)
DUDY(c,t)
DUDZ(c,t)
DVDX(c,t)
DVDY(c,t)
DVDZ(c,t)
DWDX(c,t)
DWDY(c,t)
DWDZ(c,t)
DP(c,t)[i]
D DENSITY(c,t)[i]
t
t
t
t
t
t
t
t
t
t
t
c,
c,
c,
c,
c,
c,
c,
c,
c,
c,
c,
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Returns
*t
*t
*t
*t
*t
*t
*t
*t
*t
*t, int i
*t, int i
Source
Properties
Name(Arguments) Argument Types
C
C
C
C
C
C
R(c,t)
MU L(c,t)
MU T(c,t)
MU EFF(c,t)
K L(c,t)
K T(c,t)
t
t
t
t
t
t
c,
c,
c,
c,
c,
c,
Thread
Thread
Thread
Thread
Thread
Thread
C K EFF(c,t)
cell t c, Thread
C CP(c,t)
C RGAS(c,t)
C DIFF L(c,t,i,j)
cell t
cell t
cell t
int j
cell t
cell t
cell t
C DIFF EFF(c,t,i)
C ABS COEFF(c,t)
C SCAT COEFF(c,t)
cell
cell
cell
cell
cell
cell
c, Thread
c, Thread
c, Thread
Returns
density
laminar viscosity
turbulent viscosity
eective viscosity
thermal conductivity
turbulent thermal
conductivity
*t
eective thermal
conductivity
*t
specic heat
*t
gas constant
*t, int i, laminar species diusivity
*t
*t
*t
*t
*t
*t
Source
mem.h
35
36
c;
f;
*t;
*d;
begin_c_loop(c,t)
{
}
end_c_loop(c,t)
*/
begin_f_loop(f,t)
{
}
end_f_loop(f,t)
*/
thread_loop_c(t,d)
{
}
thread_loop_f(t,d)
{
}
*/
For example, suppose you read a case le and, in the process, load a user-dened function.
If that function performs a calculation using variables that have not yet been initialized,
such as the velocity at interior cells, an error will occur. To avoid this kind of error, an
if else condition can be added to your code. If (if) the data are available, the function
can be computed in the normal way. If not (else), no (or some trivial) calculation can be
performed instead. Once the
ow eld has been initialized, the function can be reinvoked
so that the correct calculation can be performed.
2.10.9 Function for Setting Face Values
The macro F PROFILE is used to set the value of a variable at a face. This function is
used when you are generating boundary condition proles.
face_t f;
Thread *t;
F_PROFILE(f,t,nvar)
/*
from mem.h
*/
The arguments of F PROFILE are the indices of the face f, a pointer to the face's thread
t, and an integer nvar. The value that is used for nvar is passed to the UDF by the
solver. You do not specify this value in your UDF.
The integer nvar is a numerical label for the variable that is being set at a particular
boundary. For example, an inlet boundary may have a total pressure and a total temperature associated with it (both of which can be functions). One of these will be identied
by the integer 0, and the other by the integer 1. If, instead, the inlet has three velocity
components and a static temperature, they will be identied by integers 0 through 3, and
so forth. The solver sets these integers once you have dened your boundary conditions
using the Boundary Conditions panel in a FLUENT session.
! The integer nvar is a quantity that you should not change. Its value will be passed to
your UDF by FLUENT.
c
37
particle diameter
particle velocity, i=0,1,2
particle temperature
particle density
particle mass
current time for particle
particle time step
particle liquid fraction (wet combusting particles only)
particle volatile fraction (combusting particles only)
Values of particle properties at entry to the current cell:
P_DIAM(p)
P_VEL(p)[i]
P_T(p)
P_RHO(p)
P_MASS(p)
P_TIME(p)
P_DT(p)
P_LF(p)
P_VFF(p)
P_DIAM0(p)
P_VEL0(p)[i]
P_T0(p)
P_RHO0(p)
P_MASS0(p)
P_TIME0(p)
P_LF0(p)
38
particle diameter
particle velocity, i=0,1,2
particle temperature
particle density
particle mass
particle time
particle liquid fraction (wet combusting particles only)
particle diameter
particle mass
particle density
particle temperature
particle liquid fraction (wet combusting particles only)
evaporating species index in mixture
devolatizing species index in mixture
oxidizing species index in mixture
combustion products species index in mixture
current particle law index
next particle law index
storage array for user-dened values (indexed by i)
39
40
Recall that UDFs are dened using DEFINE macros that are stored in the udf.h le.
Consequently, before you compile your UDF, the udf.h le needs to be accessible in
your path, or saved locally within your working directory.
The location of the udf.h le is:
+
where path is the directory in which you have placed the release directory, Fluent.Inc,
and x is replaced by the appropriate number for the release you have (e.g., 0 for fluent5.0).
! In general, you should not copy udf.h from the release area. The compiler is designed to
look for this le locally (in your current directory) rst. If it is not found in your current
directory, the compiler will look in the /src directory automatically. In the event that
you upgrade your release area, but do not remove an old copy of udf.h from your working
directory, you will not be accessing the most recent version of this le.
! You should not, under any circumstances, alter the le udf.h.
42
1. Make sure that the C source code for your UDF, and your case le (if previously
set up) reside in your working directory, unless you are using the parallel version of
FLUENT on a network of Windows NT machines, in which case you should follow
the instructions in Section 3.2.2.
If your source code is not in your working directory, then when you compile the
UDF you must enter the le's complete path in the Interpreted UDFs panel, instead
of just the lename.
2. Start FLUENT from your working directory.
3. Read (or set up) your case le.
4. Compile your UDF (e.g., vprofile.c) using the Interpreted UDFs panel.
Dene ! User-Dened ! Functions ! Interpreted...
!
c
43
The name of your source code le (or the complete path to it) will be stored
in your case le when you write it.
(b) Specify the C preprocessor to be used in the CPP Command Name eld.
If you installed the /contrib component from the \PrePost" CD, then by
default, the cpp preprocessor will appear in the panel. For Windows NT
users, the standard Windows NT installation of the FLUENT product includes
the cpp preprocessor.
There are also a number of other ANSI C preprocessors that may be available on your system, including gcc -E and cc -E. Check with your computer
system administrator for details.
(c) Keep the default Stack Size setting of 10000, unless the number of local variables in your function will cause the stack to over
ow. In this case, set the
Stack Size to a number that is greater than the number of local variables used.
(d) Click Compile to compile your UDF.
The name and contents of your C routine will be stored in your case le when
you write the case le. If the Display Assembly Listing option in the Interpreted
UDFs panel is on (the default status), a listing of assembly language code will
appear in your console window when the function compiles. In addition, this
option will be saved in your case le, so that when you read the case in a
subsequent FLUENT session, the code will appear in the console window as
the function compiles.
44
inlet_x_velocity:
.local.pointer thread (r0)
.local.int nv (r1)
0
.local.end
0
save
.local.int f (r3)
1
push.int 0
.local.pointer x (r4)
3
begin.data 8 bytes, 0 bytes initialized:
7
save
.
.
.
.
.
.
156
pre.inc.int f (r3)
158
pop.int
159
b .L3 (22)
.L2:
161
restore
162
restore
163
ret.v
1. In the Fluent.Inc directory, create a subdirectory called udf with write permission.
2. Create a subdirectory under udf (e.g., Fluent.Inc\udf\myudf) and put the C
source code for your UDF in this directory. If multiple users are running jobs on
the same cluster, each user can create his or her own subdirectory under udf (e.g.,
Fluent.Inc\udf\abcudf and xyzudf).
Since your source code is not in your working directory, when you compile the UDF
you must enter the le's complete path in the Interpreted UDFs panel, instead of just
the lename. For example, to compile example.c, you would enter the following:
45
replacing <fileserver> with the name of the computer on which FLUENT is installed (e.g., myserver).
3. If you have already set up your case le, make sure that it resides in your working
directory.
3.2.3 Debugging Interpreted UDFs
If there are compilation errors when you compile your UDF, they will appear in the
console window. However, you may not see all the error messages if they scroll o the
screen too quickly. For this reason, you may want to turn o the Display Assembly Listing
option while debugging your UDF.
If you keep the Interpreted UDFs panel open while you are in the process of debugging
your UDF, the Compile button can be used repeatedly since you can make changes with
an editor in a separate window. Then, you can continue to debug and compile until no
errors are reported.
3.2.4 Common Errors Made While Compiling Your Interpreted
UDF
Specifying the Source File Name
You can type just the name of your C source code (e.g., vprofile.c) in the Interpreted
UDFs panel only if you launched FLUENT from your working directory and your case le
and C source code le are located in your working directory. If the C source code you
want to compile is located in a dierent directory, then you must type the complete path
to the C source code le when you compile the UDF. If you forget to do this, you'll get
the following error:
gcc: vprofile.c: No such file or directory
gcc: No input files
Error: vprofile.c: line 1: syntax error.
If you compile your UDF, write the case le, and subsequently move your C source code
to a dierent location, then when you try to read the case le during a later FLUENT
session, you will get the same error message noted above.
Workaround
To work around this error, type the complete path to the C source code under Source
File Name in the Interpreted UDFs panel, and click Compile. When you write the case le,
the new path to your C source code will be saved.
46
The general procedure for compiling and linking a compiled UDF is as follows:
1. In your working directory, set up the specied directory structure (see Section 3.3.1).
2. Compile your UDF and build the shared library (see Section 3.3.2).
3. Start FLUENT from your working directory.
4. Read (or set up) your case le. (Make sure that your case le, if previously set up,
is saved in your working directory.)
5. Link your shared library to the FLUENT executable (see Section 3.3.3).
47
where path is the directory in which you have placed the release directory, Fluent.Inc,
and x is replaced by the appropriate number for the release you have (e.g., 0 for fluent5.0).
The procedure below outlines steps that you need to follow in order to set up the directory
structure required for the shared library. To better illustrate the process, an example
directory structure is provided. Please refer to Figure 3.3.1 during specic steps of the
procedure.
Note that the directory structure shown in Figure 3.3.1 is for two versions of FLUENT:
single-precision serial 2D and single-precision parallel 2D.
! Do not put any les in the version directories (2d, 2d host, etc.). The les shown there
in Figure 3.3.1 will be placed there automatically when you compile your libraries as
described in Section 3.3.2.
libudf
src
Makefile
makefile
ultra
udfexample.c
2d
makefile udfexample.c
libudf.so
2d_host
makefile udfexample.c
2d_node
libudf.so
makefile udfexample.c
libudf.so
Figure 3.3.1: Sample Library Directory Setup for a Compiled UDF (UNIX)
48
1. In your working directory, make a directory that will store your library (e.g.,
libudf).
2. Copy Makefile.udf from the directory shown above to your library directory (e.g.,
libudf), and name it Makefile.
3. In the library directory you just created, make a source directory for your source
code, and name it src.
4. Copy your source code (e.g., udfexample.c) to your /src directory.
5. Copy makefile.udf from the directory shown above to your /src directory, and
name it makefile.
6. Identify the architecture of the machine that you will run FLUENT on.
(a) Start FLUENT.
(b) Scroll up the FLUENT console window to the message that begins with \Starting",
and identify the FLUENT architecture (e.g., ultra).
(c) Exit FLUENT.
If the architecture is irix6.5, you will need to make an extra modication to the
makefile. See Section 3.3.2 for details.
7. Create directories for the versions you want to build for your architecture (e.g.,
ultra/2d and ultra/3d). Possible versions are as follows:
single-precision serial 2D or 3D: 2d or 3d
double-precision serial 2D or 3D: 2ddp or 3ddp
single-precision parallel 2D or 3D: 2d node and 2d host or 3d node and 3d host
double-precision parallel 2D or 3D: 2ddp node and 2ddp host or 3ddp node
and 3ddp host
Note that you must create two build directories for each parallel version of the solver
(two for the 3D version, two for the 2D double-precision version, etc.), regardless
of the number of compute nodes.
Do not put any les in the version directories (2d, 2d host, etc.). The les shown
there in Figure 3.3.1 will be placed there automatically when you compile your
libraries as described in Section 3.3.2.
!
!
49
Windows NT Systems
For compiled UDFs on Windows NT systems, two Fluent Inc. les are required to build
your compiled UDF library: makefile nt.udf and user nt.udf. The le user nt.udf
has a user-modiable section that allows you to enter your source function(s) and other
information.
The procedure below outlines steps that you need to follow in order to set up the directory
structure required for the shared library. To better illustrate the process, an example
directory structure is provided. Please refer to Figure 3.3.2 during specic steps of the
procedure.
Note that the directory structure shown in Figure 3.3.2 is for two versions of FLUENT:
single-precision serial 2D and single-precision parallel 2D.
libudf
src
ntx86
udfexample.c
2d
makefile
user_nt.udf
2d_host
makefile
user_nt.udf
2d_node
makefile
user_nt.udf
Figure 3.3.2: Sample Library Directory Setup for a Compiled UDF (Windows NT)
1. In your working directory, create a directory that will store your library (e.g.,
libudf).
2. In the library directory you just created, make a source directory for your source
code, and name it src.
3. Copy your source code (e.g., udfexample.c) to your src directory.
4. Create a directory for the architecture of the machine that you will run FLUENT
on: use ntx86 for Intel systems running Windows NT, or ntalpha for DEC Alpha
systems running Windows NT.
5. Create directories for the versions you want to build for your architecture (e.g.,
ntx86\2d). Possible versions are as follows:
single-precision serial 2D or 3D: 2d or 3d
double-precision serial 2D or 3D: 2ddp or 3ddp
50
path\Fluent.Inc\fluent5.x \src\makefile_nt.udf
+
path\Fluent.Inc\fluent5.x \src\user_nt.udf
where path is the directory in which you have placed the release directory, Fluent.Inc,
and x is replaced by the appropriate number for the release you have (e.g., 2 for
fluent5.2).
Be sure that you use the most up-to-date version of these les. If you install
a new version of FLUENT 5, remember to copy the new makefile nt.udf and
user nt.udf les to the appropriate build directory.
7. Change the name of makefile nt.udf to makefile.
51
1. Edit the le makefile in your src directory to set the following parameters:
SOURCES = the user-dened function(s) to be compiled
FLUENT INC = the path to your release directory
An excerpt from a sample makefile is shown below:
#-----------------------------------------------------------#
# makefile for user defined functions.
#
# sccs id: @(#)makefile.udf
1.6 06/26/98
#-----------------------------------------------------------#
#-----------------------------------------------------------#
# User modifiable section.
#-----------------------------------------------------------#
SOURCES= udfexample.c
FLUENT_INC= /path/Fluent.Inc
#-----------------------------------------------------------#
# Build targets (do not modify below this line).
#-----------------------------------------------------------#
.
.
.
52
2. If your architecture is irix6.5, make the following additional change to the makefile.
(a) Find the following line in the makefile:
CFLAGS_IRIX6R10=
CFLAGS_IRIX6R10=
For all other architectures, do not make any further changes to the makefile.
3. In your library directory (e.g., libudf), execute the Makefile by typing a command
that begins with make and includes the architecture of the machine you will run
FLUENT on that you identied in a previous step (e.g., ultra).
make "FLUENT ARCH=ultra"
For the sample makefile above, the user-dened function udfexample.c will be
compiled and stored in the shared library named libudf.so for the versions you
have specied (2d, 2d host, and 2d node in this case, as shown in Figure 3.3.1).
Although only one C function was used in this example, you can specify multiple
sources (separated by spaces) under SOURCES = in the makefile.
53
Windows NT Systems
After you have set up your directory and put the les in the proper places, you can
compile and build your shared library.
1. Using a text editor, edit the le user nt.udf to set the following parameters:
SOURCES = the user-dened function(s) to be compiled. Use the prex $(SRC)
before each lename (e.g., $(SRC)udfexample.c for one function, or
$(SRC)udfexample.c $(SRC)udfexample2.c for two functions).
VERSION = the version of the solver you are using, which will be the name of the
build directory in which user nt.udf is located, as shown in Figure 3.3.2 (2d,
3d, 2ddp, 3ddp, 2d host, 2d node, 3d host, 3d node, 2ddp host, 2ddp node,
3ddp host, or 3ddp node).
PARALLEL NODE = the parallel communications library. Specify none for a
serial version of the solver. The possible inputs are as follows:
{ none: serial
{ smpi: parallel using shared memory (for multiprocessor machines)
{ vmpi: parallel using shared memory or network with vendor MPI software
{ net: parallel using network communicator with RSHD software
If you are using a parallel version of the solver, be sure to edit both copies of
user nt.udf (the one in the host directory and the one in the node directory), and
specify the appropriate SOURCE, VERSION, and PARALLEL NODE for each.
An excerpt from a sample user nt.udf le is shown below:
# Replace text in " " (and remove quotes)
# | indicates a choice
# note: $(SRC) is defined in the makefile
SOURCES = $(SRC)udfexample.c
VERSION = 2d
PARALLEL_NODE = none
To specify multiple user-dened functions, enter them for SOURCES, separated by
spaces.
2. In an MS-DOS Command Prompt window, go to your build directory (e.g.,
\libudf\ntx86\2d\), and type nmake.
Note that if there are problems with the build, you can do a complete rebuild by
typing nmake clean.
54
55
You will also get this error message if you move a shared library to a dierent location,
and then try to read a case le that is linked to that shared library.
Workaround
To work around this error, type the complete path to the shared library under Library
Name in the Compiled UDFs panel, and click Open. You will get the same error message
again, but the new path will be saved in your case le when you write it. Reading the
case le again, after it is written with the new path stored, will result in a successful link.
Using a Dierent Version of FLUENT
If you compile your UDF using one version of FLUENT (e.g., 5.0.1), and try to read
in your case le using a dierent version of the code (e.g., 5.0.2), you will get an error
message:
Error: open_udf_library: library version 5.0.1 incompatible with solver
version 5.0.2
Workaround
You will need to recompile your UDF using the new version of FLUENT before reading
in the case le.
56
UDFs for boundary conditions are dened with the DEFINE PROFILE macro. See Section 2.5.6 for details.
58
UDFs for source terms are dened with the DEFINE SOURCE macro. See Section 2.5.10
for details.
59
60
Then, select the desired UDF (e.g., cell viscosity) in the User-Dened Functions panel.
! If you plan to dene density using a UDF, note that the solution convergence will become
poor as the density variation becomes large. Specifying a compressible law (density as
a function of pressure) or multiphase behavior (spatially varying density) may lead to
divergence. It is recommended that you restrict the use of UDFs for density to weakly
compressible
ows with mild density variations.
UDFs for properties are dened with the DEFINE PROPERTY macro. See Section 2.5.7 for
details.
61
If you are using a \scalar update" function to calculate scalar values associated with
particles during their trajectories, you can select it from the Scalar Update drop-down list
in the Discrete Phase Model panel. You will also need to specify the Number of Scalars,
as shown in the panel above. See Section 2.6 for more information about DEFINE macros
for the discrete phase model.
62
63
64
4.10 Particle or Droplet Diameter for the Algebraic Slip Mixture Model
The DEFINE DRIFT DIAM macro is used to provide a new denition for the particle or
droplet diameter. See Section 2.7.1 for more information about the DEFINE DRIFT DIAM
macro.
65
66
67
68
UDFs for user-dened scalar transport equations (Section 5.3), the discrete phase model
(Section 5.4), and wall heat
ux (Section 5.6) are examples of compiled UDFs. In all of
the other examples, the UDFs are executed as interpreted UDFs.
For each example given in the following sections, the set of equations that is modeled
by the UDF is presented, as well as the C source code that implements the theory. See
Section 2.4.3 for descriptions of DEFINE functions (e.g., DEFINE SOURCE), and the udf.h
le or Appendix A for precise denitions. Refer to Section 2.10 for a description of
Fluent-provided solver functions (e.g., C CENTROID), or see the appropriate .h le for
denitions.
Examples of UDFs
y
0:1 105 0:0745
2
70
begin_f_loop(f, thread)
{
F_CENTROID(x,f,thread);
y = x[1];
F_PROFILE(f, thread, position) = 1.1e5 - y*y/(.0745*.0745)*0.1e5;
}
end_f_loop(f, thread)
The function named pressure profile has two arguments: thread and position.
thread is a pointer to the face's thread, and position is an integer that is a numerical
label for the variable being set within each loop.
Within the function body, variable f is declared as a face. A one-dimensional array x
and variable y are declared as real data types. Following the variable declarations, a
looping macro is used to loop over each face in the zone to create a prole, or an array
of data. Within each loop, F CENTROID returns the value of the face centroid (array x)
for the face with index f that is on the thread pointed to by thread. The y coordinate
stored in x[1] is assigned to variable y, and is then used to calculate the pressure. This
value is then assigned to F PROFILE, which uses the integer position (passed to it by
the solver based on your selection of the UDF as the boundary condition for pressure in
the Pressure Inlet panel) to set the pressure face value in memory.
71
Examples of UDFs
1=7
y
A fully-developed prole occurs when is one-half the duct height. In this example,
the mean x-velocity is prescribed and the peak (free-stream) velocity is determined by
averaging across the channel.
The turbulent kinetic energy is assumed to vary linearly from a near wall value of
knw =
u2
C
q
to a free-stream value of
kinf = 0:002u2free
where the mixing length ` is the minimum of y and 0.085. ( is the von Karman
constant = 0.41.)
The friction velocity and wall shear take the forms
u
w =
w = fu2free=2
= 0:045
ufree
! 1=4
/************************************************************************/
/* UDF for specifying fully-developed profile boundary conditions
*/
/************************************************************************/
#include "udf.h"
#define
#define
#define
#define
#define
#define
#define
#define
/*
*/
*/
/* variable declarations */
h = YMAX - YMIN;
del = DELOVRH*h;
ufree = UMEAN*(B+1.);
begin_f_loop(f, thread)
{
F_CENTROID(x,f,thread);
y = x[1];
if (y <= del)
F_PROFILE(f,thread,position) = ufree*pow(y/del,B);
else
F_PROFILE(f,thread,position) = ufree*pow((h-y)/del,B);
}
end_f_loop(f, thread)
}
/*
*/
73
Examples of UDFs
}
end_f_loop(f, thread)
/*
74
F_PROFILE(f,thread,position)=pow(CMU,0.75)*pow(kay,1.5)/mix;
}
end_f_loop(f,thread)
75
Examples of UDFs
x
0:005
The boundary condition is applied to a bottom wall that is 0.005 m long. The wall
temperature starts at 300 K at the left end, reaches a peak of 400 K in the middle, and
falls back to 300 K at the right end.
The C source code for this UDF is shown below.
/**************************************************************************/
/* UDF for specifying a sinusoidal temperature profile boundary condition */
/**************************************************************************/
#include "udf.h"
#define PI 3.141592654
DEFINE_PROFILE(temperature_profile, thread, position)
{
real r[ND_ND]; /* this will hold the position vector */
real x;
face_t f;
76
begin_f_loop(f, thread)
{
F_CENTROID(r,f,thread);
x = r[0];
F_PROFILE(f, thread, position) = 300.+100.*sin(PI*x/0.005);
}
end_f_loop(f, thread)
source = 0:5C2yjvxjvx
Suppose
source = S =
Ajvx jvx
where
A = 0:5C2 y
Then
dS
dvx
Ajvx j Avx
d
(jv j)
dvx x
Ajvx jvx
and the derivative of the source term with respect to vx (true for both positive and
negative values of vx) is
dS
dvx
= 2Ajvxj
77
Examples of UDFs
/**************************************************************/
/* UDF for specifying an x-momentum source term
*/
/**************************************************************/
#include "udf.h"
#define C2 100.0
DEFINE_SOURCE(xmom_source, cell, thread, dS, eqn)
{
real x[ND_ND];
real con, source;
C_CENTROID(x, cell, thread);
con = C2*0.5*C_R(cell, thread)*x[1];
source = -con*fabs(C_U(cell, thread))*C_U(cell, thread);
dS[eqn] = -2.*con*fabs(C_U(cell, thread));
}
78
return source;
ap
@S
@ P
=
=
@S
( )
@ P !P;old
@S
@ P;old
(5.2-1)
(5.2-2)
(5.2-3)
= 1020 (P;desired
= 1020
P )
(5.2-4)
(5.2-5)
the solver will be forced to return the desired value of as the solution at point P . This
is due to the fact that contributions from neighboring cells are lost to machine round-o.
To set this up, you need to enter both the entire linearized source term expression and the
derivative of the source term with respect to the variable being solved. For this example,
the linearized source term is
source = 1020 (r
vswirl )
where r
is the value you want to \x", and vswirl is the variable being solved. In FLUENT,
the swirling component of the velocity is C WSWIRL. The derivative of the source term is
then
dS =
1020
79
Examples of UDFs
return source;
The macro C WSWIRL(cell,thread) is used to get the tangential velocity (in the direction) for 2D axisymmetric swirl problems.
80
r~ r~ G + S G = 0
(5.3-1)
= 3a + (31 C )
s
(5.3-2)
S G = a 4T 4
@S G
@G
(5.3-3)
(5.3-4)
0 0 Ew
[4Ib(Tiw ) G0 + 0(G)]
A Ew + A
4
Tw4 Ew + A [G0
Gw =
Ew + A
0
Ew =
@S T
@T
c
2 (2
0 (G)]
w
= 16aT 3
(5.3-6)
(5.3-7)
w )
a 4T 4
(5.3-5)
(5.3-8)
(5.3-9)
81
Examples of UDFs
In addition to compiling and linking the UDFs, as described in Chapter 3, you will need
to enable the solution of a user-dened scalar transport equation in FLUENT.
Dene ! Models !User-Dened Scalars...
See Section 8.10 of the FLUENT 5 User's Guide for more details.
/**************************************************************/
/* Implementation of the P1 model using user-defined scalars */
/**************************************************************/
#include "udf.h"
#include "sg.h"
#include "prop.h"
/* Define which user-defined scalars to use. */
enum
{
P1,
N_REQUIRED_UDS
};
static
static
static
static
real
real
real
real
DEFINE_ADJUST(p1_adjust, domain)
{
/* Make sure there are enough user defined-scalars. */
if (n_uds < N_REQUIRED_UDS)
Internal_Error("not enough user-defined scalars allocated");
}
DEFINE_SOURCE(energy_source, c, t, dS, eqn)
{
dS[eqn] = -16.*abs_coeff*SIGMA_SBC*pow(C_T(c,t),3.);
return -abs_coeff*(4.*SIGMA_SBC*pow(C_T(c,t),4.) - C_UDSI(c,t,P1));
}
82
face_t f;
real A[ND_ND],At;
real dG[ND_ND],dr0[ND_ND],es[ND_ND],ds,A_by_es;
real aterm,alpha0,beta0,gamma0,Gsource,Ibw;
real Ew = epsilon_w/(2.*(2. - epsilon_w));
Thread *t0=thread->t0;
/* Do nothing if areas aren't computed yet or not next to fluid. */
if (!Data_Valid_P() || !FLUID_THREAD_P(t0)) return;
begin_f_loop (f,thread)
{
cell_t c0 = F_C0(f,thread);
BOUNDARY_FACE_GEOMETRY(f,thread,A,ds,es,A_by_es,dr0);
At = NV_MAG(A);
if (NULLP(T_STORAGE_R_NV(t0,SV_UDSI_G(P1))))
Gsource = 0.; /* if gradient not stored yet */
else
BOUNDARY_SECONDARY_GRADIENT_SOURCE(Gsource,SV_UDSI_G(P1),
dG,es,A_by_es,1.);
gamma0
alpha0
beta0
aterm
=
=
=
=
C_UDSI_DIFF(c0,t0,P1);
A_by_es/ds;
Gsource/alpha0;
alpha0*gamma0/At;
Ibw = SIGMA_SBC*pow(WALL_TEMP_OUTER(f,thread),4.)/M_PI;
83
Examples of UDFs
The DEFINE ADJUST function instructs FLUENT to check that the proper number of
user-dened scalars has been dened (in the User-Dened Scalars panel). To pass this
instruction to FLUENT, you will need to hook the p1 adjust UDF to the code using the
User-Dened Function Hooks panel.
Dene ! User-Dened ! Function Hooks...
See Section 4.6 for details.
The p1 diffusivity UDF species the incident radiation diusivity ( in Equation 5.3-2).
To use it in your FLUENT model, rst select user-dened from the UDF Diusivity dropdown list in the Materials panel, and then select p1 diusivity from the User-Dened Functions panel.
The p1 source UDF species the source term for the incident radiation equation (S G
in Equation 5.3-3) and its derivative (Equation 5.3-4). The macro SIGMA SB gives the
value of the Stefan-Boltzmann constant, = 5.672 10 8 W/m2K4 . To use this UDF in
your FLUENT model, select p1 source from the User dened scalar-0 drop-down list under
Source Terms in the Fluid panel.
The energy source UDF species the source term for the energy equation (S T in Equation 5.3-8) and its derivative (Equation 5.3-9). To use this UDF in your model, select
energy source from the Energy drop-down list under Source Terms in the Fluid panel.
The p1 bc UDF species the incident radiation boundary condition (Equation 5.3-5). The
macro FLUID THREAD P(t0) is used to determine if a cell thread is a
uid (rather than
a solid) thread. BOUNDARY FACE GEOMETRY(f,thread,A,ds,es,A by es,dr0) computes
the face area, cell, and face centroids, as well as the distance between the cell and face
centroids. The macro NULLP(T STORAGE R NV(t0,SV UDSI G(P1))) is used to check if
the gradient of the user-dened scalar with index P1 has been allocated. To use this
UDF in your model, select p1 bc in the appropriate boundary condition panel.
84
melting index =
Zt
0
1 dt
(5.4-1)
Also included in this UDF is an initialization function DEFINE INIT that is used to
initialize the scalar variables. The DPM OUTPUT function is used to write out the melting
index at sample planes and surfaces. The macro NULL P, which expands to ((p) ==
NULL), checks if its argument is a null pointer.
/***********************************************************************/
/* UDF for computing the melting index along a particle trajectory
*/
/***********************************************************************/
#include "udf.h"
#include "sg.h"
#include "dpm.h"
static real viscosity_0;
DEFINE_INIT(melt_setup, domain)
{
/* if memory for the particle variable titles has not been
* allocated yet, do it now */
if (NULLP(user_particle_vars)) Init_User_Particle_Vars();
/* now set the name and label */
85
Examples of UDFs
strcpy(user_particle_vars[0].name,"melting-index");
strcpy(user_particle_vars[0].label,"Melting Index");
}
else
{
p->user[0] = 0.;
viscosity_0 = c->mu;
86
}
else
{
"time","melt-index","name");
sprintf(name,"%s:%d",p->injection->name,p->part_id);
cxprintf(fp,
"((%10.6g %10.6g %10.6g %10.6g %10.6g %10.6g "
"%10.6g %10.6g %10.6g %10.6g %10.6g) %s)\n",
p->state.pos[0], p->state.pos[1], p->state.pos[2],
p->state.V[0], p->state.V[1], p->state.V[2],
p->state.diam, p->state.temp, p->flow_rate, p->state.time,
p->user[0], name);
87
Examples of UDFs
*/
*/
*/
DEFINE_DPM_BODY_FORCE(particle_body_force, p, i)
{
float bforce;
if(P_TIME(p)>=TSTART)
{
if(i==0) bforce=Q*BZ*P_VEL(p)[1];
else if(i==1) bforce=-Q*BZ*P_VEL(p)[0];
}
else
bforce=0.0;
/* an acceleration should be returned */
return (bforce/P_MASS(p));
}
88
89
Examples of UDFs
thread_loop_c (thread,domain)
{
begin_c_loop_all (c,thread)
{
C_CENTROID(xc,c,thread);
if (sqrt(ND_SUM(pow(xc[0] - 0.5,2.),
pow(xc[1] - 0.5,2.),
pow(xc[2] - 0.5,2.))) < 0.25)
C_T(c,thread) = 400.;
else
C_T(c,thread) = 300.;
}
end_c_loop_all (c,thread)
}
The macro ND SUM(a, b, c) that is used in the UDF computes the sum of the rst two
arguments (2D) or all three arguments (3D). It is useful for writing functions involving
vector operations so that the same function can be used for 2D and 3D. For a 2D case,
the third argument is ignored.
90
h = 120;
91
Examples of UDFs
92
begin_c_loop (c,t)
{
real T = C_T(c,t);
C_UDSI(c,t,T4) = pow(T,4.);
}
end_c_loop (c,t)
thread_loop_f (t,domain)
{
if (NULL != THREAD_STORAGE(t,SV_UDS_I(T4)))
{
begin_f_loop (f,t)
{
real T = 0.;
if (NULL != THREAD_STORAGE(t,SV_T))
T = F_T(f,t);
else if (NULL != THREAD_STORAGE(t->t0,SV_T))
T = C_T(F_C0(f,t),t->t0);
F_UDSI(f,t,T4) = pow(T,4.);
}
end_f_loop (f,t)
}
}
/* Fill second UDS with magnitude of gradient. */
thread_loop_c (t,domain)
{
if (NULL != THREAD_STORAGE(t,SV_UDS_I(T4)) &&
NULL != T_STORAGE_R_NV(t,SV_UDSI_G(T4)))
{
begin_c_loop (c,t)
{
C_UDSI(c,t,MAG_GRAD_T4) = NV_MAG(C_UDSI_G(c,t,T4));
}
end_c_loop (c,t)
}
}
thread_loop_f (t,domain)
{
if (NULL != THREAD_STORAGE(t,SV_UDS_I(T4)) &&
93
Examples of UDFs
NULL != T_STORAGE_R_NV(t->t0,SV_UDSI_G(T4)))
begin_f_loop (f,t)
{
F_UDSI(f,t,MAG_GRAD_T4) = C_UDSI(F_C0(f,t),t->t0,MAG_GRAD_T4);
}
end_f_loop (f,t)
94
Tmax
Tmin
Tmin
and stores it in user memory location 0 (which is allocated as described in Section 4.13).
Once you execute the UDF (as described in Section 4.12), the eld values for f (T ) will
be available in the drop-down lists in postprocessing panels in FLUENT. You can select
this eld by choosing udm-0 in the User Dened Memory... category. If you write a data
le after executing the UDF, the user-dened memory eld will be saved to the data le.
The C source code (demand.c) for this UDF is shown below.
/**********************************************************************/
/* demand.c
*/
/* UDF to calculate temperature field function and store in
*/
/* user-defined memory. Also print min, max, avg temperatures.
*/
/**********************************************************************/
#include "udf.h"
extern Domain* domain;
DEFINE_ON_DEMAND(demo_calc)
{
float tavg = 0.;
float tmax = 0.;
float tmin = 0.;
float temp,volume,vol_tot;
Thread *t;
cell_t c;
/* Loop over all cells in the domain */
thread_loop_c(t,domain)
{
/* Compute max, min, volume-averaged temperature */
begin_c_loop(c,t)
{
95
Examples of UDFs
volume = C_VOLUME(c,t);
temp = C_T(c,t);
Tmax = %g
Tavg = %g\n",tmin,tmax,tavg);
*/
*/
begin_c_loop(c,t)
{
temp = C_T(c,t);
C_UDMI(c,t,0) = (temp-tmin)/(tmax-tmin);
}
end_c_loop(c,t)
}
The extern Domain* domain line denes the domain, since it is not explicitly passed
as an argument of the function. The function, named demo calc, does not take any
explicit arguments. Within the function body, rst the variables to be used are dened
and initialized. Following the variable declarations, a looping macro is used to loop over
each thread (zone) in the domain. Within that loop another loop is used to loop over
each cell in each thread. Within the inner loop, the total cell volume and the minimum,
maximum, and volume-averaged temperature are computed. These computed values are
printed to the FLUENT console. Then a second loop over each cell in each thread is used
to compute the function f (T ) and store it in user-dened memory location 0.
96
All of the examples in this chapter are taken directly from Chapter 24 of the FLUENT
5 User's Guide. The volume reaction rate example (Section 6.4) illustrates a problem
setup using a compiled UDF. The remaining applications use UDFs that are executed as
interpreted UDFs.
6.1 Boundary Condition Applications
This section contains two applications of boundary condition UDFs. Both are executed
as interpreted UDFs in FLUENT.
Section 6.1.1: Parabolic Velocity Inlet Prole for a Turbine Vane
Section 6.1.2: Transient Velocity Inlet Prole for Flow in a Tube
Sample Applications
5.98e+01
5.42e+01
4.86e+01
4.30e+01
3.74e+01
3.19e+01
2.63e+01
2.07e+01
1.51e+01
9.54e+00
3.96e+00
98
6.11e+01
5.52e+01
4.93e+01
4.34e+01
3.75e+01
3.16e+01
2.57e+01
1.98e+01
1.39e+01
7.96e+00
2.05e+00
y 2
20 0:0745
where the variable y is 0.0 at the center of the inlet, and extends to values of 0.0745 m
at the top and bottom. Thus the x velocity will be 20 m/sec at the center of the inlet,
and 0 at the edges.
A user-dened function is used to introduce this parabolic prole at the inlet. The C
source code (vprofile.c) for this UDF is shown below. This UDF makes use of Fluentprovided solver functions that are described in Section 2.10.
/*************************************************************************/
/* vprofile.c
*/
/* UDF for specifying a steady-state velocity profile boundary condition */
/*************************************************************************/
#include "udf.h"
DEFINE_PROFILE(inlet_x_velocity, thread, position)
{
real x[ND_ND]; /* this will hold the position vector */
real y;
face_t f;
99
Sample Applications
begin_f_loop(f, thread)
{
F_CENTROID(x,f,thread);
y = x[1];
F_PROFILE(f, thread, position) = 20. - y*y/(.0745*.0745)*20.;
}
end_f_loop(f, thread)
The function named inlet x velocity has two arguments: thread and position.
Thread is a pointer to the face's thread, and position is an integer that is a numerical
label for the variable being set within each loop.
The function begins by declaring variable f as a face t data type. A one-dimensional
array x and variable y are declared as real data types. A looping macro is then used to
loop over each face in the zone to create a prole, or an array of data. Within each loop,
F CENTROID outputs the value of the face centroid (array x) for the face with index f
that is on the thread pointed to by thread. The y coordinate stored in x[1] is assigned
to variable y, and is then used to calculate the x velocity. This value is then assigned
to F PROFILE, which uses the integer position (passed to it by the solver based on your
selection of the UDF as the boundary condition for x velocity in the Velocity Inlet panel)
to set the x velocity face value in memory.
To make use of this interpreted UDF in FLUENT, you must rst compile it.
Dene ! User-Dened ! Functions !Interpreted...
In the Interpreted UDFs panel, name your function in the Source File Name eld. If
necessary, enter your C preprocessor type in the CPP Command Name eld and the size
of the stack under Stack Size. Click on Compile and then Close the panel. By default, an
assembly listing will be displayed in your console window as the function compiles.
100
To select this user-dened function as the velocity boundary condition for the zone of
choice, open the Velocity Inlet panel.
In the X-Velocity drop-down list, select udf inlet x velocity, the name that was given to the
function above. This function will now be used, rather than the value of (in this example)
20 that appears in the X-Velocity eld. Click on OK to accept the new boundary condition
and close the panel.
After the solution is run to convergence, a revised velocity eld is obtained as shown in
Figures 6.1.4 and 6.1.5. The velocity eld shows a maximum at the center of the inlet,
which drops to zero at the edges.
101
Sample Applications
4.46e+01
4.05e+01
3.64e+01
3.23e+01
2.83e+01
2.42e+01
2.01e+01
1.60e+01
1.19e+01
7.78e+00
3.68e+00
102
(6.1-1)
The tube is 1 m long with a radius of 0.2 m. It is assumed to be lled with air with a
density of 1 kg/m3 and a viscosity of 210 5 kg/m-s. The velocity of the air
uctuates
about an equilibrium value, v0 , of 20 m/s, with an amplitude of 5 m/s and at a frequency
of 10 rad/s.
The C source code (unsteady.c) for the UDF is shown below.
/***********************************************************************/
/* unsteady.c
*/
/* UDF for specifying a transient velocity profile boundary condition */
/***********************************************************************/
#include "udf.h"
DEFINE_PROFILE(unsteady_velocity, thread, position)
{
face_t f;
begin_f_loop(f, thread)
{
real t = RP_Get_Real("flow-time");
F_PROFILE(f, thread, position) = 20. + 5.0*sin(10.*t);
}
end_f_loop(f, thread)
The function that is dened in the UDF by the DEFINE macro is named unsteady velocity.
A real variable, flow time, is created for the time. The function RP GET REAL("flow-time")
is used to look up the real
ow time from a list that is kept by the Scheme interpreter.
Before you can compile this UDF, you must specify an unsteady
ow calculation.
Dene ! Models !Solver...
103
Sample Applications
Next you can open the Interpreted UDFs panel. Enter the name of the function in the text
entry box under Source File Name and, if necessary, the name of your C preprocessor.
Click on Compile and then Close the panel.
Dene ! User-Dened ! Functions !Interpreted...
The sinusoidal velocity boundary condition dened by the UDF can now be selected
for the X-Velocity in the inlet zone. In the Velocity Inlet panel, simply select udf unsteady velocity in the drop-down list to the right of the X-Velocity eld, and click on
OK.
104
In this example, a Time Step Size of 0.0314 s is used so that 20 time steps will complete
a full period of oscillation in the inlet velocity. The number of iterations to be performed
at each time step is limited to 20. This number of iterations is not enough to obtain
a converged
ow eld in the early stages of the solution, but will very likely result in
converged time steps after a few time steps have passed. The UDF Prole Update Interval
is set to 1 so that the velocity will be updated every iteration. After 60 time steps (or 3
periods) are complete, you can examine the velocity magnitude across the pressure outlet
for its response to the oscillating inlet condition.
105
Sample Applications
To collect this information during the calculation, open the Surface Monitors panel before
beginning to iterate.
Solve ! Monitors !Surface...
Increase the Surface Monitors index to 1. This will enable you to dene the parameters
of monitor-1 (which you could rename, if desired, in the text entry box under Name).
Select Plot so that the selected quantity will be plotted as the calculation proceeds. Select
Print to see the changing values of the selected quantity in the console window. Select
Write so that the information will be written to a le, which will be given the name
monitor-1.out. (If you change the name of the monitor, that name will be used as the
prex for the output le.)
Under Every, you can choose Iteration, Time Step, or Flow Time. To monitor the result
of each time step, you should choose the Time Step option. By clicking on Dene... you
can specify the quantity to be monitored in the Dene Surface Monitor panel.
106
In this example, Velocity... and Velocity Magnitude are chosen in the drop-down lists
under Report Of. The location of the report is pressure-outlet-5, which is selected in the
Surfaces list. A simple Average is chosen in the Report Type drop-down list, with the Flow
Time chosen in the X Axis drop-down list.
Once the desired number of iterations has been completed, the monitor should appear in
the chosen plot window. Alternatively, you can read the le by opening the File XY Plot
panel.
Plot !File...
You can read the output le by typing its name in the text entry box under Files and
clicking on Add.... By selecting this le and clicking on Plot, you can obtain the plot
c
107
Sample Applications
Average
Velocity
Magnitude
2.00e+01
1.90e+01
1.80e+01
1.70e+01
1.60e+01
1.50e+01
0
0.2
0.4
0.6
0.8
1.2
1.4
1.6
1.8
Flow Time
108
(6.2-1)
where C is a constant. As the liquid cools, its motion will be reduced to zero, simulating
the formation of the solid. (In this simple example, the energy equation will not be
customized to account for the latent heat of freezing. The velocity eld will be used only
as an indicator of the solidication region.)
The solver linearizes source terms in order to enhance the stability and convergence of a
solution. To allow the solver to do this, you need to specify the dependent relationship
between the source and solution variables in your UDF, in the form of derivatives. The
source term, Sx, depends only on the solution variable, vx. Its derivative with respect to
vx is
@Sx
@vx
(6.2-2)
109
Sample Applications
Density
Viscosity
Specic Heat
Thermal Conductivity
Value
8000 kg/m3
5.5 10 3 kg/m-s
680 J/kg-K
30 W/m-K
To add the source term and specify its derivative, the following C function is used.
#include "udf.h"
#define CON 20.0
DEFINE_SOURCE(cell_x_source, cell, thread, dS, eqn)
{
real source;
if (C_T(cell,thread) <= 288.)
{
/* source term */
source = -CON*C_U(cell,thread);
/* derivative of source term w.r.t. x-velocity. */
dS[eqn] = -CON;
}
else
source = dS[eqn] = 0.;
}
return source;
The function is called cell x source, and it is dened on a cell. The constant C in
Equation 6.2-1 is called CON in the function, and it is given a numerical value of 20
kg/m3-s, which will result in the desired units of N/m3 for the source. The temperature
at the cell is C T(cell,thread). The function checks to see if the temperature is below
(or equal to) 288 K. If it is, the source is computed according to Equation 6.2-1 (C U
returns the value of the x velocity of the cell). If it is not, the source is set to 0.0. At
the end of the function, the appropriate value for the source is returned.
This function is executed as an interpreted UDF (see Section 3.2). To include it in the
calculation, you will specify it as a source term in the Fluid panel.
110
To include a source term in the
uid, activate the Source Terms button. You can then
add source terms for Mass, Momentum, and Energy (visible by moving the slide bar).
(Note that in other applications, sources for other problem variables would also become
available at this time.) To select the user-dened source for the X Momentum, select udf
cell x source in the drop-down list and click on OK.
Once the solution has converged, you can view contours of static temperature to see the
cooling eects of the wall on the liquid metal as it moves through the duct (Figure 6.2.1).
111
Sample Applications
2.90e+02
2.89e+02
2.87e+02
2.86e+02
2.84e+02
2.83e+02
2.81e+02
2.80e+02
2.78e+02
2.77e+02
2.75e+02
Contours of Static Temperature (k)
Source Term Application
112
The solidication is further illustrated by line contours of stream function (Figure 6.2.3).
8.00e+00
7.20e+00
6.40e+00
5.60e+00
4.80e+00
4.00e+00
3.20e+00
2.40e+00
1.60e+00
8.00e-01
0.00e+00
Contours of Stream Function (kg/s)
Source Term Application
113
Sample Applications
0:49725T
(6.3-1)
This model is based on the assumption that as the liquid cools and rapidly becomes more
viscous, its velocity will decrease, thereby simulating solidication. Here, no correction
is made for the energy eld to include the latent heat of freezing.
The C source code (viscosity.c) for this example is shown below.
/***********************************************************************/
/* viscosity.c
*/
/* UDF for specifying a temperature-dependent viscosity property
*/
/***********************************************************************/
#include "udf.h"
DEFINE_PROPERTY(cell_viscosity, cell, thread)
{
real mu_lam;
real temp = C_T(cell, thread);
if (temp > 288.)
mu_lam = 5.5e-3;
else if (temp > 286.)
mu_lam = 143.2135 - 0.49725 * temp;
else
114
return mu_lam;
The function cell viscosity is dened on a cell and uses the DEFINE PROPERTY macro.
Two real variables are introduced: temp, the value of C T(cell,thread), and mu lam,
the laminar viscosity computed by the function. The value of the temperature is checked,
and based upon the range into which it falls, the appropriate value of mu lam is computed.
At the end of the function, the computed value for mu lam is returned.
To make use of a user-dened property, you will use the Materials panel. In the drop-down
list for Viscosity, select the user-dened option.
Once you select this option, the User-Dened Functions panel opens, from which you
can select the appropriate function name. In this example, only one is available, but in
another example, you might have several functions from which to choose. (Recall that if
you need to compile more than one interpreted UDF, the functions can be concatenated
prior to compiling. See Chapter 3 for details.)
c
115
Sample Applications
The results of this model are similar to those obtained in Section 6.2.1. Figure 6.3.1
shows the viscosity eld resulting from the application of the user-dened function. The
viscosity varies rapidly over a narrow spatial band from a constant value of 0.0055 to
1.0 kg/m-s.
The velocity eld (Figure 6.3.2) demonstrates that the liquid slows down in response to
the increased viscosity, as expected. In this model, there is a large \mushy" region, in
which the motion of the
uid gradually decreases. This is in contrast to the rst model,
in which a momentum source was applied and a more abrupt change in the
uid motion
was observed.
1.00e+00
9.01e-01
8.01e-01
7.02e-01
6.02e-01
5.03e-01
4.03e-01
3.04e-01
2.04e-01
1.05e-01
5.50e-03
Contours of Molecular Viscosity (kg/m-s)
Physical Property Application
116
1.73e-03
1.55e-03
1.38e-03
1.21e-03
1.04e-03
8.63e-04
6.91e-04
5.18e-04
3.45e-04
1.73e-04
0.00e+00
Contours of Velocity Magnitude (m/s)
Physical Property Application
Figure 6.3.2: Contours of Velocity Magnitude Resulting from a User-Dened Viscosity
8.00e+00
7.20e+00
6.40e+00
5.60e+00
4.80e+00
4.00e+00
3.20e+00
2.40e+00
1.60e+00
8.00e-01
0.00e+00
Contours of Stream Function (kg/s)
Physical Property Application
117
Sample Applications
K1 Xa
(1 + K2Xa )2
(6.4-1)
Grid
porous medium itself, where there is an inertial resistance of 5 m 1 in each of the two
coordinate directions. The laminar
ow eld (Figure 6.4.2) shows that most of the gas
is diverted from the porous region into the open region.
1.62e+00
1.46e+00
1.30e+00
1.14e+00
9.73e-01
8.11e-01
6.49e-01
4.87e-01
3.24e-01
1.62e-01
0.00e+00
Figure 6.4.3: Velocity Vectors for the 2D Duct with a Porous Region
The C le (rate.c) that contains the UDF used to model the reaction taking place in
the porous region is shown below.
c
119
Sample Applications
/**************************************************************/
/* rate.c
*/
/* UDF for specifying a reaction rate in a porous media
*/
/**************************************************************/
#include "udf.h"
#define K1 2.0e-2
#define K2 5.
DEFINE_VR_RATE(user_rate, cell, thread, r, mole_weight, species_mf, rate, rr_t)
{
real s1 = species_mf[0];
real mw1 = mole_weight[0];
In the C function, a function named user rate is dened on a cell for a given species
mass fraction. The UDF performs a test to check for the porous region, and only applies
the reaction rate equation to the porous region.
The macro FLUID THREAD P(thread) is used to determine if a cell thread is a
uid (rather
than a solid) thread. The variable THREAD VAR(thread).fluid.porous is used to check
if a
uid cell thread is a porous region.
To use this UDF, set up a directory named librate to hold the library directory structure. Then build a shared library as described in Chapter 3.
Next, start your FLUENT session, and either read in your case le or set it up. Open the
library that was built during the Makefile process, and link it to the FLUENT executable
by specifying librate as the Library Name in the Compiled UDFs panel and clicking Open.
120
User-Dened
Functions
! Compiled...
Now you can specify user rate as the reaction rate by selecting it in the Volume Reaction
Rate Function drop-down list in the User-Dened Function Hooks panel.
Dene ! User-Dened ! Function Hooks...
Initialize and run the calculation. The converged solution for the mass fraction of
species-a is shown in Figure 6.4.4. The gas that moves through the porous region
is gradually converted to species-b in the horizontal section of the duct. No reaction
takes place in the
uid region, although some diusion of species-b out of the porous
region is suggested by the wide transition layer between the regions of 100% and 0%
species-a.
121
Sample Applications
1.00e+00
9.00e-01
8.00e-01
7.00e-01
6.00e-01
5.00e-01
4.00e-01
3.00e-01
2.00e-01
1.00e-01
0.00e+00
Figure 6.4.4: Mass Fraction for species-a Governed by a Reaction in a Porous Region
122
DEFINE
124
t) \
c, Thread *t)
domain) \
*domain)
pow (double x,
y);
exp (double x);
log (double x);
log10 (double x);
fabs (double x);
ceil (double x);
floor (double x);
xy
ex
ln(x)
log10(x)
jxj
smallest integer not less than x
largest integer not greater than x
C Library Functions
The functions fopen and fclose open and close a le, respectively. The function fprintf
writes to a le in a specied format, and the function fscanf reads from a le in the
same manner. The function printf is a general-purpose printing function. The symbol
*fd that appears in many of the functions is simply a pointer that identies the le. All
of the functions except fopen are declared as integers, since a given integer value will
indicate whether the function (say, to read from a le) was executed successfully or not.
For more information about standard I/O functions in C, you should consult a reference
guide, or, on UNIX machines, view the manual pages.
126