The DEFINE
macros presented in this section implement general
solver functions that are independent of the model(s) you are using in Ansys Fluent. Table 2.1: Quick Reference Guide for General Purpose DEFINE Macros provides a quick reference guide to these
DEFINE
macros, the functions they are used to define, and the
dialog boxes where they are activated or "hooked" to Ansys Fluent. Definitions of each
DEFINE
macro are contained in udf.h
can
be found in Appendix B: DEFINE
Macro Definitions.
- 2.2.1. DEFINE_ADJUST
- 2.2.2. DEFINE_DELTAT
- 2.2.3. DEFINE_EXECUTE_AT_END
- 2.2.4. DEFINE_EXECUTE_AT_EXIT
- 2.2.5. DEFINE_EXECUTE_FROM_GUI
- 2.2.6. DEFINE_EXECUTE_ON_LOADING
- 2.2.7. DEFINE_EXECUTE_AFTER_CASE/DATA
- 2.2.8. DEFINE_INIT
- 2.2.9. DEFINE_ON_DEMAND
- 2.2.10. DEFINE_REPORT_DEFINITION_FN
- 2.2.11. DEFINE_RW_FILE
- 2.2.12. DEFINE_RW_HDF_FILE
Table 2.1: Quick Reference Guide for General Purpose DEFINE Macros
Function |
|
Dialog Box Activated In |
---|---|---|
manipulates variables |
|
User-Defined Function Hooks |
time step size (for time-dependent solutions) |
|
Run Calculation task page |
executes at end of iteration |
|
User-Defined Function Hooks |
executes at end of an Ansys Fluent session |
|
User-Defined Function Hooks |
executes from a user- defined Scheme routine |
|
N/A |
executes when a UDF library is loaded |
|
N/A |
executes after a case file is read |
|
N/A |
executes after a data file is read |
|
N/A |
initializes variables |
|
User-Defined Function Hooks |
executes asynchronously |
|
Execute On Demand |
returns a value for a user defined report definition |
|
User Defined Report Definition |
reads/writes variables to legacy case and data files |
|
User-Defined Function Hooks |
reads/writes variables to CFF case and data files |
|
User-Defined Function Hooks |
DEFINE_ADJUST
is a general-purpose macro that can be used to
adjust or modify Ansys Fluent variables that are not passed as arguments.
For example, you can use DEFINE_ADJUST
to modify flow variables
(for example, velocities, pressure) and compute integrals. You can also use it to
integrate a scalar quantity over a domain and adjust a boundary condition based on the
result. A function that is defined using DEFINE_ADJUST
executes
at every iteration and is called at the beginning of every iteration before transport
equations are solved. For an overview of the Ansys Fluent solution process which shows when a
DEFINE_ADJUST
UDF is called, refer to Figure 1.2: Solution Procedure for the Pressure-Based Segregated Solver, Figure 1.3: Solution Procedure for the Pressure-Based Coupled Solver,
and Figure 1.4: Solution Procedure for the Density-Based Solver.
DEFINE_ADJUST
(name
,
d
)
Argument Type |
Description |
---|---|
|
UDF name. |
|
Pointer to the domain over which the adjust function is to be applied. The domain argument provides access to all cell and face threads in the mesh. For multiphase flows, the pointer that is passed to the function by the solver is the mixture-level domain. |
Function returns
void
There are two arguments to DEFINE_ADJUST
:
name
and d
. You supply
name
, the name of the UDF. d
is passed
by the Ansys Fluent solver to your UDF.
The following UDF, named my_adjust
, integrates the turbulent
dissipation over the entire domain using DEFINE_ADJUST
. This
value is then displayed in the console. The UDF is called once every iteration. It can be
executed as an interpreted or compiled UDF in Ansys Fluent.
/******************************************************************** UDF for integrating turbulent dissipation and displaying it in the console *********************************************************************/ #include "udf.h" DEFINE_ADJUST(my_adjust,d) { Thread *t; /* Integrate dissipation. */ real sum_diss=0.; cell_t c; thread_loop_c(t,d) { begin_c_loop(c,t) sum_diss += C_D(c,t)* C_VOLUME(c,t); end_c_loop(c,t) } printf("Volume integral of turbulent dissipation: %g\n", sum_diss); }
The following UDF, named adjust_fcn
, specifies a user-defined
scalar as a function of the gradient of another user-defined scalar, using
DEFINE_ADJUST
. The function is called once every iteration. It
is executed as a compiled UDF in Ansys Fluent.
/******************************************************************** UDF for defining user-defined scalars and their gradients *********************************************************************/ #include "udf.h" DEFINE_ADJUST(adjust_fcn,d) { Thread *t; cell_t c; real K_EL = 1.0; /* Do nothing if gradient isn’t allocated yet. */ if (! Data_Valid_P()) return; thread_loop_c(t,d) { if (FLUID_THREAD_P(t)) { begin_c_loop(c,t) { C_UDSI(c,t,1) += K_EL*NV_MAG2(C_UDSI_G(c,t,0))*C_VOLUME(c,t); } end_c_loop(c,t) } } }
The following UDF, named calc_vof_grad
, calculates the
reconstruction gradients and gradients for the volume fraction using
DEFINE_ADJUST
. The magnitude and components of the gradients
are then stored in UDMs. This UDF requires declaration of 4 UDMS.
#include "udf.h" #include "sg.h" #include "sg_mphase.h" DEFINE_ADJUST(calc_vof_grad, d) { #if !RP_HOST Domain *sd; Thread *t; cell_t c; /* subdomain pointer for first secondary phase */ sd = DOMAIN_SUB_DOMAIN(d, 1); /* alloc memory for volume fraction reconstruction gradient and gradient */ Alloc_Storage_Vars(sd, SV_VOF_RG, SV_VOF_G, SV_NULL); /* calculate reconstruction gradient */ Scalar_Reconstruction(sd, "rp-global", SV_VOF, -1, SV_VOF_RG, NULL); /* calculate gradient */ Scalar_Derivatives(sd, "rp-global", SV_VOF, -1, SV_VOF_G, SV_VOF_RG, Vof_Deriv_Accumulate); thread_loop_c(t, sd) { if (FLUID_THREAD_P(t) && SV_ALLOCATED_P(t, SV_VOF_G)) { begin_c_loop(c, t) { Thread *tm = THREAD_SUPER_THREAD(t); /* fill in udms */ C_UDMI(c, tm, 0) = NV_MAG(C_VOF_G(c,t)); C_UDMI(c, tm, 1) = C_VOF_G(c,t)[0]; C_UDMI(c, tm, 2) = C_VOF_G(c,t)[1]; #if RP_3D C_UDMI(c, tm, 3) = C_VOF_G(c,t)[2]; #endif } end_c_loop(c ,t) } else { Message0("Warning: Zone %d is either not a fluid thread or C_VOF_G is not available.\n", THREAD_ID(t)); } } /* free memory */ Free_Storage_Vars(sd, SV_VOF_RG, SV_VOF_G, SV_NULL); #endif }
After the UDF that you have defined using DEFINE_ADJUST
is
interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
adjust_fcn
) will become visible and selectable via the
User-Defined Function Hooks dialog box in Ansys Fluent. Note that you
can hook multiple adjust functions to your model. See Hooking DEFINE_ADJUST
UDFs for details.
DEFINE_DELTAT
is a general-purpose macro that you can use to
control the size of the time step during the solution of a transient problem. Note that
this macro can be used only if User-Defined Function is selected from
the Type drop-down list in the Run Calculation
task page in Ansys Fluent.
DEFINE_DELTAT
(name
,
d
)
Argument Type |
Description |
---|---|
|
UDF name. |
|
Pointer to domain over which the time stepping control function is to be applied. The domain argument provides access to all cell and face threads in the mesh. For multiphase flows, the pointer that is passed to the function by the solver is the mixture-level domain. |
Function returns
real
There are two arguments to DEFINE_DELTAT
:
name
and domain
. You supply
name
, the name of the UDF. domain
is
passed by the Ansys Fluent solver to your UDF. Your UDF will need to compute the
real
value of the physical time step and return it to the
solver.
The following UDF, named mydeltat
, is a simple function that
shows how you can use DEFINE_DELTAT
to change the value of the
time step in a simulation. First, CURRENT_TIME
is used to get the
value of the current simulation time (which is assigned to the variable
flow_time
). Then, for the first 0.5
seconds of the calculation, a time step of 0.1
is set. A time
step of 0.2
is set for the remainder of the simulation. The time
step variable is then returned to the solver. See Time-Dependent Macros
for details on CURRENT_TIME
.
/********************************************************************* UDF that changes the time step value for a time-dependent solution **********************************************************************/ #include "udf.h" DEFINE_DELTAT(mydeltat,d) { real time_step; real flow_time = CURRENT_TIME; if (flow_time < 0.5) time_step = 0.1; else time_step = 0.2; return time_step; }
After the UDF that you have defined using
DEFINE_DELTAT
is interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (e.g,.
mydeltat
) will become visible and selectable in the
Run Calculation task page in Ansys Fluent. See Hooking DEFINE_DELTAT
UDFs for details.
DEFINE_EXECUTE_AT_END
is a general-purpose macro that is executed
at the end of an iteration in a steady-state run, or at the end of a time step in a
transient run. You can use DEFINE_EXECUTE_AT_END
when you want to
calculate flow quantities at these particular times. Note that you do not have to specify
whether your execute-at-end UDF gets executed at the end of a time step or the end of an
iteration. This is done automatically when you select the steady or unsteady time method
in your Ansys Fluent model.
DEFINE_EXECUTE_AT_END
(name
)
Argument Type |
Description |
---|---|
|
UDF name. |
Function returns
void
There is only one argument to DEFINE_EXECUTE_AT_END
:
name
. You supply name
, the name of the
UDF. Unlike DEFINE_ADJUST
,
DEFINE_EXECUTE_AT_END
is not passed a domain pointer.
Therefore, if your function requires access to a domain pointer, then you will need to use
the utility Get_Domain(ID)
to explicitly obtain it (see Domain Pointer (Get_Domain
) and the example below). If your UDF requires
access to a phase domain pointer in a multiphase solution, then it will need to pass the
appropriate phase ID to Get_Domain
in order to obtain it.
The following UDF, named execute_at_end
, integrates the
turbulent dissipation over the entire domain using
DEFINE_EXECUTE_AT_END
and displays it in the console at the end
of the current iteration or time step. It can be executed as an interpreted or compiled
UDF in Ansys Fluent.
/******************************************************************** UDF for integrating turbulent dissipation and displaying it in the console at the end of the current iteration or time step *********************************************************************/ #include "udf.h" DEFINE_EXECUTE_AT_END(execute_at_end) { Domain *d; Thread *t; /* Integrate dissipation. */ real sum_diss=0.; cell_t c; d = Get_Domain(1); /* mixture domain if multiphase */ thread_loop_c(t,d) { if (FLUID_THREAD_P(t)) { begin_c_loop(c,t) sum_diss += C_D(c,t) * C_VOLUME(c,t); end_c_loop(c,t) } } printf("Volume integral of turbulent dissipation: %g\n", sum_diss); fflush(stdout); }
After the UDF that you have defined using
DEFINE_EXECUTE_AT_END
is interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
execute_at_end
) will become visible and selectable via the
User-Defined Function Hooks dialog box in Ansys Fluent. Note that you
can hook multiple end-iteration functions to your model. See Hooking DEFINE_EXECUTE_AT_END
UDFs for details.
DEFINE_EXECUTE_AT_EXIT
is a general-purpose macro that can be
used to execute a function at the end of an Ansys Fluent session.
DEFINE_EXECUTE_AT_EXIT
(name
)
Argument Type |
Description |
---|---|
|
UDF name. |
Function returns
void
There is only one argument to DEFINE_EXECUTE_AT_EXIT
:
name
. You supply name
, the name of the
UDF.
After the UDF that you have defined using
DEFINE_EXECUTE_AT_EXIT
is interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument will become visible and
selectable via the User-Defined Function Hooks dialog box in
Ansys Fluent. Note that you can hook multiple at-exit UDFs to your model. For details, see
Hooking DEFINE_EXECUTE_AT_EXIT
UDFs.
DEFINE_EXECUTE_FROM_GUI
is a general-purpose macro that you can
use to define a UDF which is to be executed from a user-defined graphical user interface
(GUI). For example, a C function that is defined using
DEFINE_EXECUTE_FROM_GUI
can be executed whenever a button is
clicked in a user-defined GUI. Custom GUI components (dialog boxes, buttons, and so on)
are defined in Ansys Fluent using the Scheme language.
DEFINE_EXECUTE_FROM_GUI
(name
,
libname
, mode
)
Argument Type |
Description |
---|---|
|
UDF name. |
|
name of the UDF library that has been loaded in Ansys Fluent. |
|
an integer passed from the Scheme program that defines the user-defined GUI. |
Function returns
void
There are three arguments to DEFINE_EXECUTE_FROM_GUI
: name,
libname, and mode. You supply name, the name of the UDF. The variables
libname
and mode
are passed by the
Ansys Fluent solver to your UDF. The integer variable mode
is passed
from the Scheme program which defines the user-defined GUI, and represent the possible
user options available from the GUI dialog box. A different C function in UDF can be
called for each option. For example, the user-defined GUI dialog box may have a number of
buttons. Each button may be represented by different integers, which, when clicked, will
execute a corresponding C function.
Important:
DEFINE_EXECUTE_FROM_GUI
UDFs must be implemented as compiled
UDFs, and there can be only one function of this type in a UDF library.
The following UDF, named reset_udm
, resets all user-defined
memory (UDM) values when a reset button on a user-defined GUI dialog box is clicked. The
clicking of the button is represented by , which is passed to the UDF by the Ansys Fluent solver.
/********************************************************* UDF called from a user-defined GUI dialog box to reset all user-defined memory locations **********************************************************/ #include "udf.h" DEFINE_EXECUTE_FROM_GUI(reset_udm, myudflib, mode) { Domain *domain = Get_Domain(1); /* Get domain pointer */ Thread *t; cell_t c; int i; /* Return if mode is not zero */ if (mode != 0) return; /* Return if no User-Defined Memory is defined in Ansys Fluent */ if (n_udm == 0) return; /* Loop over all cell threads in domain */ thread_loop_c(t, domain) { /* Loop over all cells */ begin_c_loop(c, t) { /* Set all UDMs to zero */ for (i = 0; i < n_udm; i++) { C_UDMI(c, t, i) = 0.0; } } end_c_loop(c, t); } }
After the UDF that you have defined using
DEFINE_EXECUTE_FROM_GUI
is compiled (Compiling UDFs), the function will not need
to be hooked to Ansys Fluent through any graphics dialog boxes. Instead, the function will be
searched automatically by the Ansys Fluent solver when the execution of the UDF is requested
(that is, when a call is made from a user-defined Scheme program to execute a C
function).
DEFINE_EXECUTE_ON_LOADING
is a general-purpose macro that can be
used to specify a function that executes as soon as a compiled UDF library is loaded in
Ansys Fluent. This is useful when you want to initialize or set up UDF models when a UDF
library is loaded. (Alternatively, if you save your case file when a shared library is
loaded, then the UDF will execute whenever the case file is subsequently read.)
Compiled UDF libraries are loaded using either the Compiled UDFs
or the UDF Library Manager dialog box (see Load and Unload Libraries Using the UDF Library Manager Dialog Box). An EXECUTE_ON_LOADING
UDF
is the best place to reserve user-defined scalar (UDS) and user-defined memory (UDM) for a
particular library (Reserve_User_Scalar_Vars
and Reserving UDM Variables Using Reserve_User_Memory_Vars
) as well as set UDS and UDM names (
Set_User_Scalar_Name
and Set_User_Memory_Name
).
Important:
DEFINE_EXECUTE_ON_LOADING
UDFs can be executed only as compiled
UDFs.
Note: Using the DEFINE_EXECUTE_ON_LOADING
UDF for renaming DPM
scalars is not recommended because it may cause an abnormal termination of Ansys Fluent
while reading a DPM case with such a UDF. This occurs because the
DEFINE_EXECUTE_ON_LOADING
type UDF is executed prior to the
DPM model being enabled. Instead, you should use the
DEFINE_EXECUTE_AFTER_CASE
UDF to accomplish this task.
DEFINE_EXECUTE_ON_LOADING
(name
,
libname
)
Argument Type |
Description |
---|---|
|
UDF name. |
|
compiled UDF library name. |
Function returns
void
There are two arguments to DEFINE_EXECUTE_ON_LOADING
:
name
and libname
. You supply a name
for the UDF which will be used by Ansys Fluent when reporting that the
EXECUTE_ON_LOADING
UDF is being run. The
libname
is set by Ansys Fluent to be the name of the library (for
example, libudf
) that you have specified (by entering a name or
keeping the default libudf
). libname
is
passed so that you can use it in messages within your UDF.
The following simple UDF named report_version
, prints a
message on the console that contains the version and release number of the library being
loaded.
#include "udf.h" static int version = 1; static int release = 2; DEFINE_EXECUTE_ON_LOADING(report_version, libname) { Message("\nLoading %s version %d.%d\n",libname,version,release); }
The following source code contains two UDFs. The first UDF is an
EXECUTE_ON_LOADING
function that is used to reserve three UDMs
(using Reserve_User_Memory_Vars
) for a library and set unique
names for the UDM locations (using Set_User_Memory_Name
). The
second UDF is an ON_DEMAND
function that is used to set the
values of the UDM locations after the solution has been initialized. The
ON_DEMAND
UDF sets the initial values of the UDM locations
using udm_offset
, which is defined in the on-loading UDF. Note
that the on demand UDF must be executed after the solution is
initialized to reset the initial values for the UDMs. See Reserving UDM Variables Using Reserve_User_Memory_Vars
and Set_User_Memory_Name
for more information on reserving and naming UDMs.
/********************************************************************** This file contains two UDFs: an execute on loading UDF that reserves three UDMs for libudf and renames the UDMs to enhance postprocessing, and an on-demand UDF that sets the initial value of the UDMs. **********************************************************************/ #include "udf.h" #define NUM_UDM 3 static int udm_offset = UDM_UNRESERVED; DEFINE_EXECUTE_ON_LOADING(on_loading, libname) { if (udm_offset == UDM_UNRESERVED) udm_offset = Reserve_User_Memory_Vars(NUM_UDM); if (udm_offset == UDM_UNRESERVED) Message("\nYou need to define up to %d extra UDMs in GUI and " "then reload current library %s\n", NUM_UDM, libname); else { Message("%d UDMs have been reserved by the current " "library %s\n",NUM_UDM, libname); Set_User_Memory_Name(udm_offset,"lib1-UDM-0"); Set_User_Memory_Name(udm_offset+1,"lib1-UDM-1"); Set_User_Memory_Name(udm_offset+2,"lib1-UDM-2"); } Message("\nUDM Offset for Current Loaded Library = %d",udm_offset); } DEFINE_ON_DEMAND(set_udms) { Domain *d; Thread *ct; cell_t c; int i; d=Get_Domain(1); if(udm_offset != UDM_UNRESERVED) { Message("Setting UDMs\n"); for (i=0;i<NUM_UDM;i++) { thread_loop_c(ct,d) { begin_c_loop(c,ct) { C_UDMI(c,ct,udm_offset+i)=3.0+i/10.0; } end_c_loop(c,ct) } } } else Message("UDMs have not yet been reserved for library 1\n"); }
After the UDF that you have defined using
DEFINE_EXECUTE_ON_LOADING
is compiled (Compiling UDFs), the function will not need
to be hooked to Ansys Fluent through any graphics dialog boxes. Instead, Ansys Fluent searches the
newly loaded library for any UDFs of the type EXECUTE_ON_LOADING
,
and will automatically execute them in the order they appear in the library.
DEFINE_EXECUTE_AFTER_CASE
and
DEFINE_EXECUTE_AFTER_DATA
are general-purpose macros that can
be used to specify a function that executes after the case and/or data file is read in
Ansys Fluent. This is useful because it provides access to UDF functions after the case and/or
data file is read.
Compiled UDF libraries are loaded using either the Compiled UDFs or the UDF Library Manager dialog box (see Load and Unload Libraries Using the UDF Library Manager Dialog Box).
Important:
DEFINE_EXECUTE_AFTER_CASE
and
DEFINE_EXECUTE_AFTER_DATA
UDFs can be executed only as
compiled UDFs.
DEFINE_EXECUTE_AFTER_CASE
(name
,
libname
) or
DEFINE_EXECUTE_AFTER_DATA
(name
,
libname
)
Argument Type |
Description |
---|---|
|
UDF name. |
|
compiled UDF library name. |
Function returns
void
There are two arguments to DEFINE_EXECUTE_AFTER_CASE
and
DEFINE_EXECUTE_AFTER_DATA
: name
and
libname
. You supply a name for the UDF which will be used by
Ansys Fluent when reporting that the EXECUTE_AFTER_CASE
or
EXECUTE_AFTER_DATA
UDF is being run. The
libname
is set by Ansys Fluent to be the name of the library (for
example, libudf
) that you have specified (by entering a name or
keeping the default libudf
). libname
is
passed so that you can use it in messages within your UDF.
The following simple UDF named after_case
and
after_data
, prints a message to the console that contains the
name of the library being loaded.
#include "udf.h" DEFINE_EXECUTE_AFTER_CASE(after_case, libname) { Message("EXECUTE_AFTER_CASE called from $s\n", libname); } DEFINE_EXECUTE_AFTER_DATA(after_data, libname) { Message("EXECUTE_AFTER_DATA called from $s\n", libname); }
After the UDF that you have defined using
DEFINE_EXECUTE_AFTER_CASE
or
DEFINE_EXECUTE_AFTER_DATA
is compiled (Compiling UDFs), the function will not need
to be hooked to Ansys Fluent through any graphics dialog boxes. Instead, Ansys Fluent searches the
newly loaded library for any UDFs of the type EXECUTE_AFTER_CASE
or EXECUTE_AFTER_DATA
, and will automatically execute them in the
order they appear in the library.
DEFINE_INIT
is a general-purpose macro that you can use to
specify a set of initial values for your solution. DEFINE_INIT
accomplishes the same result as patching, but does it in a different way, by means of a
UDF. A DEFINE_INIT
function is executed once per initialization
and is called immediately after the default initialization is performed by the solver.
Since it is called after the flow field is initialized, it is typically used to set
initial values of flow quantities. For an overview of the Ansys Fluent solution process which
shows when a DEFINE_INIT
UDF is called, refer to Figure 1.2: Solution Procedure for the Pressure-Based Segregated Solver, Figure 1.3: Solution Procedure for the Pressure-Based Coupled Solver,
and Figure 1.4: Solution Procedure for the Density-Based Solver.
DEFINE_INIT
(name
,
d
)
Argument Type |
Description |
|
UDF name. |
|
Pointer to the domain over which the initialization function is to be applied. The domain argument provides access to all cell and face threads in the mesh. For multiphase flows, the pointer that is passed to the function by the solver is the mixture-level domain. |
Function returns
void
There are two arguments to DEFINE_INIT
:
name
and d
. You supply
name
, the name of the UDF. d
is passed
from the Ansys Fluent solver to your UDF.
The following UDF, named my_init_func
, initializes flow field
variables in a solution. It is executed once, at the beginning of the solution process.
The function can be executed as an interpreted or compiled UDF in Ansys Fluent.
/*********************************************************************** UDF for initializing flow field variables ************************************************************************/ #include "udf.h" DEFINE_INIT(my_init_func,d) { cell_t c; Thread *t; real xc[ND_ND]; /* loop over all cell threads in the domain */ thread_loop_c(t,d) { /* loop over all cells */ begin_c_loop(c,t) { C_CENTROID(xc,c,t); 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,t) = 400.; else C_T(c,t) = 300.; } end_c_loop(c,t) } }
The macro ND_SUM(a,b,c)
computes the sum of the first 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. See Additional Macros for Writing UDFs for a
description of predefined macros such as C_CENTROID
and
ND_SUM
.
After the UDF that you have defined using DEFINE_INIT
is
interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
my_init_func
) will become visible and selectable via the
User-Defined Function Hooks dialog box in Ansys Fluent. Note that you
can hook multiple init functions to your model. See Hooking DEFINE_INIT
UDFs
for details.
DEFINE_ON_DEMAND
is a general-purpose macro that you can use to
specify a UDF that is executed "on demand" in Ansys Fluent, rather than having Ansys Fluent call
it automatically during the calculation. Your UDF will be executed immediately, after it
is activated, but it is not accessible while the solver is iterating. Note that the domain
pointer d
is not explicitly passed as an argument to
DEFINE_ON_DEMAND
. Therefore, if you want to use the domain
variable in your on-demand function, you will need to first retrieve it using the
Get_Domain
utility provided by Ansys Fluent (shown in the example
below). See Domain Pointer (Get_Domain
) for details on
Get_Domain
.
DEFINE_ON_DEMAND
(name
)
Argument Type |
Description |
|
UDF name. |
Function returns
void
There is only one argument to DEFINE_ON_DEMAND
:
name
. You supply name
, the name of the
UDF.
The following UDF, named on_demand_calc
, computes and prints
the minimum, maximum, and average temperatures for the current data field. It then
computes a temperature function
(2–1) |
and stores it in user-defined memory location (which is allocated as described in Cell Macros). After you hook the on-demand UDF (as described in Hooking DEFINE_ON_DEMAND
UDFs), the field values for will be available in drop-down lists in postprocessing dialog boxes in
Ansys Fluent. You can select this field by choosing User Memory 0 in the
User-Defined Memory... category. If you write a data file after
executing the UDF, the user-defined memory field will be saved to the data file. This
source code can be interpreted or compiled in Ansys Fluent.
/********************************************************************** UDF to calculate temperature field function and store in user-defined memory. Also print min, max, avg temperatures. ***********************************************************************/ #include "udf.h" DEFINE_ON_DEMAND(on_demand_calc) { Domain *d; /* declare domain pointer since it is not passed as an argument to the DEFINE macro */ real tavg = 0.; real tmax = 0.; real tmin = 0.; real temp,volume,vol_tot; Thread *t; cell_t c; d = Get_Domain(1); /* Get the domain using Ansys Fluent utility */ /* Loop over all cell threads in the domain */ thread_loop_c(t,d) { /* Compute max, min, volume-averaged temperature */ /* Loop over all cells */ begin_c_loop(c,t) { volume = C_VOLUME(c,t); /* get cell volume */ temp = C_T(c,t); /* get cell temperature */ if (temp < tmin || tmin == 0.) tmin = temp; if (temp > tmax || tmax == 0.) tmax = temp; vol_tot += volume; tavg += temp*volume; } end_c_loop(c,t) tavg /= vol_tot; printf("\n Tmin = %g Tmax = %g Tavg = %g\n",tmin,tmax,tavg); /* Compute temperature function and store in user-defined memory*/ /*(location index 0) */ begin_c_loop(c,t) { temp = C_T(c,t); C_UDMI(c,t,0) = (temp-tmin)/(tmax-tmin); } end_c_loop(c,t) } }
Get_Domain
is a macro that retrieves the pointer to a domain. It
is necessary to get the domain pointer using this macro since it is not explicitly passed
as an argument to DEFINE_ON_DEMAND
. The function, named
on_demand_calc
, does not take any explicit arguments. Within
the function body, the variables that are to be used by the function are defined and
initialized first. Following the variable declarations, a looping macro is used to loop
over each cell thread in the domain. Within that loop another loop is used to loop over
all the cells. Within the inner loop, the total volume and the minimum, maximum, and
volume-averaged temperature are computed. These computed values are printed to the
Ansys Fluent console. Then a second loop over each cell is used to compute the function
and store it in user-defined memory location . Refer to Additional Macros for Writing UDFs for a
description of predefined macros such as C_T
and
begin_c_loop
.
After the UDF that you have defined using DEFINE_ON_DEMAND
is
interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
on_demand_calc
) will become visible and selectable in the
Execute On Demand dialog box in Ansys Fluent. See Hooking DEFINE_ON_DEMAND
UDFs for details.
DEFINE_REPORT_DEFINITION_FN
is a macro that you can use to
specify a UDF for reporting a single-valued expression that can be plotted, written, or
printed to the console as a report definition.
The DEFINE_REPORT_DEFINITION_FN
macro takes a single
argument, name, as the name of the function you are creating. Your
user-defined function should return a real value that will be the value of the report
definition.
Note: If you need to access the value of another report definition, use the Get_Report_Definition_Values
macro.
DEFINE_REPORT_DEFINITION_FN
(name
)
Argument Type |
Description |
|
name of the user defined report definition function |
Function returns
real
This function computes the volumetric flow rate at an inlet, demonstrating the ability to perform operations on an input variable and output the result for plotting, printing, or writing to a file as part of a user-defined report definition.
#include "udf.h" DEFINE_REPORT_DEFINITION_FN(volume_flow_rate_inlet) { real inlet_velocity = Get_Input_Parameter("vel_in"); real inlet_area = 0.015607214; real volumeFlow = inlet_velocity*inlet_area; return volumeFlow; }
Note: This example uses the Get_Input_Parameter
API, indicating
that this Fluent case file has the inlet velocity specified as an input
parameter.
After the UDF that you have defined using
DEFINE_REPORT_DEFINITION_FN
is interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
on_demand_calc
) will become visible and selectable in the
User Defined Report Definition dialog box in Fluent. See User Defined Report Definition Function Hooking in the Fluent User's Guide for details.
DEFINE_RW_FILE
is a general-purpose macro that you can use to
specify customized information that is to be written to a legacy case or data file (that
is, a .cas
or .dat
file), or read from a
legacy case or data file. You can save and restore custom variables of any data type (for
example, integer, real, CXBoolean, structure) using
DEFINE_RW_FILE
. It is often useful to save dynamic information
(for example, number of occurrences in conditional sampling) while your solution is being
calculated, which is another use of this function. Note that the read order and the write
order must be the same when you use this function.
When using the DEFINE_RW_FILE
, you should be attentive to
which parts of the function should be done by the host, and which by the compute nodes.
For details, see Compiler Directives.
Important: Starting in Ansys Fluent version 18.2, the DEFINE_RW_FILE
macro
is not supported for serial UDFs in the following circumstances:
In a compiled UDF on Windows
In an interpreted UDF on any platform
As a workaround for such unsupported combinations, you can parallelize the UDF (as described in Parallelizing Your Serial UDF).
DEFINE_RW_FILE
(name
,
fp
)
Argument Type |
Description |
|
UDF name. |
|
Pointer to the legacy file you are reading or writing. |
Function returns
void
There are two arguments to DEFINE_RW_FILE
:
name
and fp
. You supply
name
, the name of the UDF. fp
is
passed from the solver to the UDF.
The following C source code listing contains examples of functions that write information to a legacy data file and read it back. These functions are concatenated into a single source file that can be interpreted or compiled in Ansys Fluent.
/*********************************************************************** UDFs that increment a variable, write it to a legacy data file and read it back in ************************************************************************/ #include "udf.h" int kount = 0; /* define global variable kount */ DEFINE_ADJUST(demo_calc,d) { kount++; printf("kount = %d\n",kount); } DEFINE_RW_FILE(writer,fp) { printf("Writing UDF data to legacy data file...\n"); #if !RP_NODE fprintf(fp,"%d",kount); /* write out kount to legacy data file */ #endif } DEFINE_RW_FILE(reader,fp) { printf("Reading UDF data from legacy data file...\n"); #if !RP_NODE fscanf(fp,"%d",&kount); /* read kount from legacy data file */ #endif }
At the top of the listing, the integer kount
is defined and
initialized to zero. The first 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
DEFINE_ADJUST
for more information about
ADJUST
functions.) The second function
(writer
) instructs Ansys Fluent to write the current value of
kount
to the legacy data file, when the legacy data file is
saved. The third function (reader
) instructs Ansys Fluent to read the
value of kount
from the legacy data file, when the data file is
read.
The functions work together as follows. If you run your calculation for, say, 10
iterations (kount
has been incremented to a value of 10) and save
the legacy data file, then the current value of kount
(10) will
be written to your legacy data file. If you read the data back into Ansys Fluent and continue
the calculation, kount
will start at a value of 10 and will be
incremented 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 in which they are
written.
After the UDF that you have defined using DEFINE_RW_FILE
is
interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
writer
) will become visible and selectable via the
User-Defined Function Hooks dialog box in Ansys Fluent. Note that you
can hook multiple read/write functions to your model. See Hooking DEFINE_RW_FILE
and
DEFINE_RW_HDF_FILE
UDFs for details.
DEFINE_RW_HDF_FILE
is a general-purpose macro that you can use to
read or write customized information from or to case or data files written in the Common
Fluids Format (CFF), that is, .cas.h5
or
.dat.h5
files. You can read and write custom datasets of real
values as well as attributes of various types.
DEFINE_RW_HDF_FILE
(name
,
filename
)
Argument Type |
Description |
|
UDF name. |
|
Name of the CFF file you are reading or writing. |
Function returns
void
There are two arguments to
DEFINE_RW_HDF_FILE
: name
and
filename
. You supply name
, the name of
the UDF. filename
is passed from the solver to the UDF. Because
of the structured nature of the Common Fluids Format, a series of helper functions are
made available for performing the low-level read/write operations. These are detailed in
Helper Functions.
CFF files use a compressed binary format. In order to make reading and writing these files easier, a series of helper functions are made available for use in your UDF. The following terminology is used in the descriptions of the helper functions:
- Datasets
can be thought of as arrays that store data. Typically the data are stored as real values.
- Groups
are analogous to directories on a file system. A group can contain other groups, datasets, or a combination of both.
- Attributes
are name/value pairs that assigned to datasets or groups and are generally used for storing metadata. For example, a dataset may have an attribute for the number of elements in the dataset.
- Link
is an umbrella term that may refer to groups or datasets, but not to attributes.
- Path
is a string representation of a link in the CFF file. The path of the root group of the file is denoted by
/
. Any link in the file can be identified by specifying the absolute path to the link (for example,/path/to/link
).
The following functions are made available by including
hdfio.h
in your UDF source file and are used to perform CFF
reading and writing. Note that all functions prepend /user
to
the provided path
parameter. Thus, all user-defined data written
or accessed by these functions is stored under the group
/user
.
Write_Complete_User_Dataset |
Write_Partial_User_Dataset |
Write_User_Attributes |
Read_Complete_User_Dataset |
Read_Partial_User_Dataset |
Read_User_Attributes |
Get_Next_User_Link_Name |
Write_Complete_User_Dataset
#include "hdfio.h"
void Write_Complete_User_Dataset
(
)
;
char*
filename
;
char*
path
;
real*
ptr
;
size_t
nelems
;-
filename
Name of the CFF file to which data is to be written. In a
DEFINE_RW_HDF_FILE
macro, this is generally passed in by Fluent.-
path
Path in the file at which the dataset will be written.
-
ptr
Pointer to the data that will be written. Note that the data type must be real.
-
nelems
Number of data elements to be written from a node.
This is the basic function for writing data to a CFF file. The
function assumes that data is only in nodes and is already arranged sequentially according
to node rank. Therefore, data in node0 is written first followed by data in node1, and so
on. A new dataset is created at path
and the size of the created
dataset is the sum of nelems
across all nodes.
Write_Partial_User_Dataset
#include "hdfio.h"
void Write_Partial_User_Dataset
(
)
;
char*
filename
;
char*
path
;
real*
ptr
;
size_t
nelems
;
size_t
datasetsize
;
size_t
datasetoffset
;-
filename
Name of the CFF file to which data is to be written. In a
DEFINE_RW_HDF_FILE
macro, this is generally passed in by Fluent.-
path
Path in the file at which the dataset will be written.
-
ptr
Pointer to the data that will be written. Note that the data type must be real.
-
nelems
Number of data elements to be written from a node.
-
datasetsize
Total size of the dataset into which the data will be written. This must be larger than the sum of
nelems
across all nodes.-
datasetoffset
The offset within the dataset at which writing will start.
This function can be used when it is desirable to write data to the same dataset through multiple calls. The dataset will be created the first time and data will be written into the dataset in subsequent calls from each compute node.
Write_User_Attributes
#include "hdfio.h"
void Write_User_Attributes
(
)
;
char*
filename
;
char*
path
;
char*
name
;
MPT_Datatype
mpttype
;
type
value
;
...
;
NULL
;-
filename
Name of the CFF file.
-
path
Path to the link in the file for which the attributes will be written.
-
name
Name of the attribute.
-
mpttype
The datatype of the attribute value. This can be one of MPT_SHORT, MPT_INT, MPT_LONG, MPT_LONG_LONG, MPT_SIZE_T, MPT_DOUBLE
-
value
Value of the attribute. The
type
of the attribute should be short, int, long, long long, size_t, or double according to the value ofmpttype
-
...
Multiple attributes can be specified by including additional triplets of
name
,mpttype
, andvalue
.-
NULL
the list of parameters must be terminated with
NULL.
Read_Complete_User_Dataset
#include "hdfio.h"
void Read_Complete_User_Dataset
(
)
;
char*
filename
;
char*
path
;
real*
ptr
;
size_t
nelems
;-
filename
Name of the CFF file from which data is to be read. In a
DEFINE_RW_HDF_FILE
macro, this is generally passed in by Fluent.-
path
Path in the file from which the dataset will be read.
-
ptr
Pointer to the location where the read data will be stored. Note that the data type is assumed to be real.
-
nelems
Number of data elements to be read into a node.
This is the basic function for reading data from an CFF file.
As in the Write_Complete_User_Data
function, the data is read
sequentially according to node rank. Therefore, data that is read first fills node0
followed by node1, and so on.
Read_Partial_User_Dataset
#include "hdfio.h"
void Read_Partial_User_Dataset
(
)
;
char*
filename
;
char*
path
;
real*
ptr
;
size_t
nelems
;
size_t
datasetoffset
;-
filename
Name of the CFF file from which data is to be read. In a
DEFINE_RW_HDF_FILE
macro, this is generally passed in by Fluent.-
path
Path in the file from which the dataset will be read.
-
ptr
Pointer to the location where the read data will be stored. Note that the data type is assumed to be real.
-
nelems
Number of data elements to be read into a node.
-
datasetoffset
The offset within the dataset at which reading will start.
This function can be used to read a portion of a dataset from a CFF file.
Read_User_Attributes
#include "hdfio.h"
void Read_User_Attributes
(
)
;
char*
filename
;
char*
path
;
char*
name
;
MPT_Datatype
mpttype
;
type*
ptr
;
...
;
NULL
;-
filename
Name of the CFF file.
-
path
Path to the link in the file for which the attributes will be read.
-
name
Name of the attribute to read.
-
mpttype
The datatype of the attribute value. This can be one of MPT_SHORT, MPT_INT, MPT_LONG, MPT_LONG_LONG, MPT_SIZE_T, MPT_DOUBLE.
-
ptr
Pointer to the location in which to store the attribute value. The pointer
type
should be short, int, long, long long, size_t, or double according to the value ofmpttype
-
...
Multiple attributes can be read by including additional triplets of
name
,mpttype
, andptr
.-
NULL
the list of parameters must be terminated with
NULL.
Get_Next_User_Link_Name
#include "hdfio.h"
void
Get_Next_User_Link_Name
(
)
;
char*
filename
;
char*
path
;
char*
prev_name
;
char*
next_name
;-
filename
Name of the CFF file.
-
path
Path to a group in the file under which the links reside.
-
prev_name
Name of a link under the group at
path
. The name of the next link afterprev_name
(based on order of creation in the document) will be returned innext_name
. A value of NULL can be used to get the first link within a group.-
next_name
The name of the link following
prev_name
is returned innext_name
. Ifprev_name
is the last link in the group, an empty string will be returned.
This function is typically used to iterate over the links under a group. The iteration
is started by passing NULL as the value for prev_name
. Iteration
continues by using the value returned in next_name
as the value of
prev_name
in the next iteration. The iteration is complete when
an empty string is returned in next_name.
/* * UDF that writes a complete dataset to a CFF file, sets an attribute for the dataset * and then reads it back. These demonstrate the use of the following helper functions: * Write_Complete_User_Dataset * Write_User_Attributes * Read_Complete_User_Dataset * Read_User_Attributes */ #include "udf.h" #include "hdfio.h" #define ELEM_COUNT 50 DEFINE_RW_HDF_FILE(write_complete_dataset, filename) { size_t i, nelems = ELEM_COUNT; real* ptr = NULL; char* path = "/test/complete_data"; /* Assign equal number of elements in all the nodes * and fill with some values. Write a dataset with * all the values at the end. Also write an attribute * with total number of elements. */ #if RP_NODE ptr = (real*)CX_Malloc(sizeof(real) * nelems); for (i = 0; i < nelems; ++i) { ptr[i] = (real)((myid + 1) * i); } #endif Write_Complete_User_Dataset(filename, path, ptr, nelems); Write_User_Attributes(filename, path, "totalElems", MPT_SIZE_T, (size_t)(nelems * compute_node_count), NULL ); if (NNULLP(ptr)) { CX_Free(ptr); } } DEFINE_RW_HDF_FILE(read_complete_dataset, filename) { size_t nelems = 0, totalElems = 0; real* ptr = NULL; char* path = "/test/complete_data"; /* Read complete dataset and check the elements. */ Read_User_Attributes(filename, path, "totalElems", MPT_SIZE_T, &totalElems, NULL ); #if RP_NODE nelems = totalElems / compute_node_count; ptr = (real*)CX_Malloc(sizeof(real) * nelems); #endif Read_Complete_User_Dataset(filename, path, ptr, nelems); if (NNULLP(ptr)) { CX_Free(ptr); } }
After the UDF that you have defined using DEFINE_RW_HDF_FILE
is interpreted (Interpreting UDFs) or compiled (Compiling UDFs), the name of the argument that you supplied as
the first DEFINE
macro argument (for example,
write_complete_dataset
) will become visible and selectable via
the User-Defined Function Hooks dialog box in Ansys Fluent. Note that you
can hook multiple read/write functions to your model. See Hooking DEFINE_RW_FILE
and
DEFINE_RW_HDF_FILE
UDFs for details.