[Fluent Inc. Logo] return to home search
next up previous contents index

7.5.1 Compiler Directives

When converting a UDF to run in parallel, some parts of the function may need to be done by the host and some by the compute nodes. This distinction is made when the UDF is compiled. By using Fluent-provided compiler directives , you can specify portions of your function to be assigned to the serial process, the host, or to the compute nodes. The UDF that you write will be written as a single file for the serial, parallel host and parallel node versions, but different parts of the function will be compiled to generate different versions of the dynamically linked shared object file libudf.so ( libudf.dll on NT/Windows). Print tasks, for example, may be assigned exclusively to the host, while a task such as computing the total volume of a complete mesh will be assigned to the compute nodes. Since most operations are executed by the serial solver and either the host or compute nodes, negated forms of compiler directives are more commonly used.

Note that the primary purpose of the host is to interpret commands from Cortex and to pass those commands (and data) to compute node-0 for distribution. Since the host does not contain grid data, you will need to be careful not to include the host in any calculations that could, for example result in a division by zero. In this case, you will need to direct the compiler to ignore the host when it is performing grid-related calculations, by wrapping those operations around the #if !RP_HOST directive. For example, suppose that your UDF will compute the total area of a face thread, and then use that total area to compute a flux. If you do not exclude the host from these operations, the total area on the host will be zero and a floating point exception will occur when the function attempts to divide by zero to obtain the flux.

Example

#if !RP_HOST
avg_pres = total_pres_a / total_area;  /* if you don't exclude the host
            this operation will result in a division by zero and error!
            Remember that host has no data so its total will be zero.*/
#endif

You will need to use the #if !RP_NODE directive when you want to exclude compute nodes from operations for which they do not have data.

Below is a list of parallel compiler directives and what they do. Note that if either RP_HOST or RP_NODE are true, then PARALLEL is also true.

/**********************************************************************/
/*   Compiler Directives                                              */
/**********************************************************************/

#if RP_HOST   
    /*  only host process is involved */
#endif 

#if RP_NODE  
    /*  only compute nodes are involved */
#endif 

#if PARALLEL  
    /* both host and compute nodes are involved, but not serial
       equivalent to #if RP_HOST || RP_NODE  */
#endif 


/*********************************************************************/
/*   Negated forms that are more commonly used                       */
/*********************************************************************/

#if !RP_HOST
    /*  either serial or compute node process is involved */
#endif 

#if !RP_NODE
    /* either serial or host process is involved */
#endif 

#if !PARALLEL   
    /*  only serial process is involved */
#endif

The following simple UDF shows the use of compiler directives. The adjust function is used to define a function called where_am_i. This function queries to determine which type of process is executing and then displays a message on that computed node's monitor.

Example

/*****************************************************
  Simple UDF that uses compiler directives         
*****************************************************/
#include "udf.h"
DEFINE_ADJUST(where_am_i, domain)
{
#if RP_HOST
  Message("I am in the host process\n");
#endif /* RP_HOST */

#if RP_NODE
  Message("I am in the node process with ID %d\n",myid);
  /* myid is a global variable which is set to the multiport ID for 
     each node */
#endif /* RP_NODE */

#if !PARALLEL
  Message("I am in the serial process\n");
#endif /* !PARALLEL */
}

This simple allocation of functionality between the different types of processes is useful in a limited number of practical situations. For example, you may want to display a message on the compute nodes when a particular computation is being run (by using RP_NODE or !RP_HOST). Or, you can also choose to designate the host process to display messages (by using RP_HOST or !RP_NODE). Usually you want messages written only once by the host process (and the serial process). Simple messages such as "Running the Adjust Function'' are straightforward. Alternatively, you may want to collect data from all the nodes and print the total once, from the host. To perform this type of operation your UDF will need some form of communication between processes. The most common mode of communication is between the host and the node processes.


next up previous contents index Previous: 7.5 Macros for Parallel
Up: 7.5 Macros for Parallel
Next: 7.5.2 Communicating Between the
© Fluent Inc. 2006-09-13