2.2. General Purpose DEFINE Macros

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.

Table 2.1: Quick Reference Guide for General Purpose DEFINE Macros

Function

DEFINE Macro

Dialog Box Activated In

manipulates variables

DEFINE_ADJUST

User-Defined Function Hooks

time step size (for time-dependent solutions)

DEFINE_DELTAT

Run Calculation task page

executes at end of iteration

DEFINE_EXECUTE_AT_END

User-Defined Function Hooks

executes at end of an Ansys Fluent session

DEFINE_EXECUTE_AT_EXIT

User-Defined Function Hooks

executes from a user- defined Scheme routine

DEFINE_EXECUTE_FROM_GUI

N/A

executes when a UDF library is loaded

DEFINE_EXECUTE_ON_LOADING

N/A

executes after a case file is read

DEFINE_EXECUTE_AFTER_CASE

N/A

executes after a data file is read

DEFINE_EXECUTE_AFTER_DATA

N/A

initializes variables

DEFINE_INIT

User-Defined Function Hooks

executes asynchronously

DEFINE_ON_DEMAND

Execute On Demand

returns a value for a user defined report definition

DEFINE_REPORT_DEFINITION_FN

User Defined Report Definition

reads/writes variables to legacy case and data files

DEFINE_RW_FILE

User-Defined Function Hooks

reads/writes variables to CFF case and data files

DEFINE_RW_HDF_FILE

User-Defined Function Hooks


2.2.1. DEFINE_ADJUST

2.2.1.1. Description

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.

2.2.1.2. Usage

DEFINE_ADJUST (name, d)

Argument Type

Description

symbol name

UDF name.

Domain *d

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.

2.2.1.3. Example 1

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);
 } 

2.2.1.4. Example 2

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)
        }
      }
 } 

2.2.1.5. Example 3

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
}

2.2.1.6. Hooking an Adjust UDF to Ansys Fluent

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.

2.2.2. DEFINE_DELTAT

2.2.2.1. Description

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.

2.2.2.2. Usage

DEFINE_DELTAT (name, d)

Argument Type

Description

symbol name

UDF name.

Domain *d

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.

2.2.2.3. Example

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;
 } 

2.2.2.4. Hooking an Adaptive Time Step UDF to Ansys Fluent

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.

2.2.3. DEFINE_EXECUTE_AT_END

2.2.3.1. Description

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.

2.2.3.2. Usage

DEFINE_EXECUTE_AT_END (name)

Argument Type

Description

symbol name

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.

2.2.3.3. Example

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);
 } 

2.2.3.4. Hooking an Execute-at-End UDF to Ansys Fluent

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.

2.2.4. DEFINE_EXECUTE_AT_EXIT

2.2.4.1. Description

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.

2.2.4.2. Usage

DEFINE_EXECUTE_AT_EXIT (name)

Argument Type

Description

symbol name

UDF name.

Function returns

void

There is only one argument to DEFINE_EXECUTE_AT_EXIT: name. You supply name, the name of the UDF.

2.2.4.3. Hooking an Execute-at-Exit UDF to Ansys Fluent

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.

2.2.5. DEFINE_EXECUTE_FROM_GUI

2.2.5.1. Description

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.

2.2.5.2. Usage

DEFINE_EXECUTE_FROM_GUI (name, libname, mode)

Argument Type

Description

symbol name

UDF name.

char *libname

name of the UDF library that has been loaded in Ansys Fluent.

int mode

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.


2.2.5.3. Example

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);
     }
 } 

2.2.5.4. Hooking an Execute From GUI UDF to Ansys Fluent

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).

2.2.6. DEFINE_EXECUTE_ON_LOADING

2.2.6.1. Description

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.


2.2.6.2. Usage

DEFINE_EXECUTE_ON_LOADING (name, libname)

Argument Type

Description

symbol name

UDF name.

char *libname

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.

2.2.6.3. Example 1

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);
 } 

2.2.6.4. Example 2

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");
 } 

2.2.6.5. Hooking an Execute On Loading UDF to Ansys Fluent

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.

2.2.7. DEFINE_EXECUTE_AFTER_CASE/DATA

2.2.7.1. Description

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.


2.2.7.2. Usage

DEFINE_EXECUTE_AFTER_CASE (name, libname) or

DEFINE_EXECUTE_AFTER_DATA (name, libname)

Argument Type

Description

symbol name

UDF name.

char *libname

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.

2.2.7.3. Example

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);
 } 

2.2.7.4. Hooking an Execute After Reading Case and Data File UDF to Ansys Fluent

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.

2.2.8. DEFINE_INIT

2.2.8.1. Description

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.

2.2.8.2. Usage

DEFINE_INIT (name, d)

Argument Type

Description

symbol name

UDF name.

Domain *d

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.

2.2.8.3. Example

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.

2.2.8.4. Hooking an Initialization UDF to Ansys Fluent

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.

2.2.9. DEFINE_ON_DEMAND

2.2.9.1. Description

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.

2.2.9.2. Usage

DEFINE_ON_DEMAND (name)

Argument Type

Description

symbol name

UDF name.

Function returns

void

There is only one argument to DEFINE_ON_DEMAND: name. You supply name, the name of the UDF.

2.2.9.3. Example

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.

2.2.9.4. Hooking an On-Demand UDF to Ansys Fluent

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.

2.2.10. DEFINE_REPORT_DEFINITION_FN

2.2.10.1. Description

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.

2.2.10.2. Usage

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

symbol name

name of the user defined report definition function

Function returns

real

2.2.10.3. Example

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.


2.2.10.4. Hooking a User Defined Report Definition to Ansys Fluent

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.

2.2.11. DEFINE_RW_FILE

2.2.11.1. Description

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).


2.2.11.2. Usage

DEFINE_RW_FILE (name, fp)

Argument Type

Description

symbol name

UDF name.

FILE *fp

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.

2.2.11.3. Example

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.

2.2.11.4. Hooking a Read/Write Legacy Case or Data File UDF to Ansys Fluent

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.

2.2.12. DEFINE_RW_HDF_FILE

2.2.12.1. Description

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.

2.2.12.2. Usage

DEFINE_RW_HDF_FILE (name, filename)

Argument Type

Description

symbol name

UDF name.

char *filename

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.

2.2.12.3. 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
    #include "hdfio.h"
    void Write_Complete_User_Dataset (filename,   path,   ptr,   nelems)
    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 (filename,   path,   ptr,   nelems,   datasetsize,   datasetoffset)
    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 (filename,   path,   name,   mpttype,   value,   ...,    NULL )
    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 of mpttype

    ...

    Multiple attributes can be specified by including additional triplets of name, mpttype, and value.

    NULL

    the list of parameters must be terminated with NULL.

    Read_Complete_User_Dataset
    #include "hdfio.h"
    void Read_Complete_User_Dataset (filename,   path,   ptr,   nelems)
    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 (filename,   path,   ptr,   nelems,   datasetoffset)
    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 (filename,   path,   name,   mpttype,   ptr,   ...,    NULL )
    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 of mpttype

    ...

    Multiple attributes can be read by including additional triplets of name, mpttype, and ptr.

    NULL

    the list of parameters must be terminated with NULL.

    Get_Next_User_Link_Name
    #include "hdfio.h"
    void Get_Next_User_Link_Name (filename,   path,   prev_name,   next_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 after prev_name (based on order of creation in the document) will be returned in next_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 in next_name. If prev_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.

    2.2.12.4. Examples

    /*
     * 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);
      }
    }
    

    2.2.12.5. Hooking a Read/Write CFF Case or Data File UDF to Ansys Fluent

    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.