Академический Документы
Профессиональный Документы
Культура Документы
Examples ____________________________________________________________________ 9
Example 1: General Usage ___________________________________________________________ 9
Example 2: Check for available gradients ______________________________________________ 21
Example 3: Gradients in DEFINE_SOURCE ______________________________________________ 22
Example 4: Temperature gradients ___________________________________________________ 29
Example 5: Locate free surface ______________________________________________________ 33
Multiphase considerations_____________________________________________________ 38
Parallel considerations ________________________________________________________ 38
Summary ___________________________________________________________________ 39
Attachments ________________________________________________________________ 39
References _________________________________________________________________ 39
If you have questions regarding this document, please try to contact the author, first:
akram.radwan@ansys.com
If you do not get feedback within two weeks, contact your local ANSYS support office.
Most examples are provided together with a test case that can be used to learn how the macros work
under different circumstances.
Important: This solution describes undocumented UDF macros. They might change in future versions
without being mentioned in the documentation. Use these Macros at your own risk.
ANSYS can decline working on support requests that use undocumented features. If you run into trouble
using undocumented features, eliminate these before contacting ANSYS support.
This document refers to the pressure-based solver. The density-based solver might behave differently.
Besides the documented gradient and reconstruction gradient macros there are two more that are
frequently requested but not documented: C_VOF_G(c, t) and C_UDSI_G(c, t, i) for volume fraction
and user-defined scalars respectively.
They can be used just like the other gradient macros.
The manual states that the temporary solver memory has not be freed when you want to use gradient or
reconstruction gradient macros. The text command required for that is /solve/set/expert.
Figure 1: Text command to keep temporary solver memory from being freed
However, this text command can be difficult to use for automation because the number of parameters
depends on the active models.
It is possible to avoid this text command completely for most cases if you follow these three steps in every
UDF in that you need access to gradient macros:
1. Allocate memory for each gradient macro you want to use. This is identical with making part of
the temporary solver memory available for the duration of the UDF execution.
2. Trigger an update of the desired reconstruction gradients and gradients
3. Optional: Free the allocated memory at the end of your UDF
These three manual steps are used in the tutorial “Multiphase Flow Modeling using ANSYS FLUENT
Tutorials : Horizontal Film Boiling” that is available on the ANSYS Customer Portal but they are not
explained there.
However, when you follow these steps and do not know what you do you risk:
Wasting memory and computation time
Errors during UDF execution
Termination of the Fluent process
However, there is a scenario where you have access to some additional gradient and reconstruction
gradient macros without additional action. You have access at least to some of the temporary solver
memory when you use a DEFINE macro that is called from within a cell loop. For example,
DEFINE_VECTOR_EXCHANGE_PROPERTY is called during a cell loop in the phase calculation of a multiphase
simulation. Therefore you have access to C_VOF_G without the need to allocate additional memory. The
second example in the customization manual uses this circumstance:
ANSYS Fluent Customization Manual > Part I. Creating and Using User Defined Functions > 2. DEFINE
Macros > 2.4. Multiphase DEFINE Macros > 2.4.7. DEFINE_VECTOR_EXCHANGE_PROPERTY >
2.4.7.4. Example 2 – Custom Turbulent Dispersion
DEFINE_SOURCE is another example where you do not need to take additional action if you access a
gradient macro of the same quantity the DEFINE_SOURCE is hooked to.
For example, if you hook your DEFINE_SOURCE UDF to the energy equation you have access to C_T_G.
But you do not have access to C_VOF_G. This example is discussed in more detail later.
Alloc_Storage_Vars
This command allocates memory for gradient and reconstruction gradient macros. It is executed on a
domain level. Never use this macro from within DEFINE macros that are executed during a cell loop. As
stated before, you should have access to the temporary solver memory for such UDFs for most of the
relevant quantities. For example, if you hook a DEFINE_SOURCE to the energy equation you should have
access to the temperature gradient regardless of other efforts to make gradients available or unavailable.
Alloc_Storage_Vars takes four arguments:
Alloc_Storage_Vars(domain, SV_*_RG, SV_*_G, SV_NULL);
domain is the domain you need the gradient for. It is either passed on by the DEFINE macro or is
obtained with Get_Domain(1) for the mixture domain. (See paragraph “Multiphase
Considerations” later in this document and also the customization manual.)
SV_*_RG and SV_*_G can be derived from the gradient macro you want to use. For temperature
gradients this would be SV_T_RG and SV_T_G respectively.
Fortunately, Alloc_Storage_Vars will not overwrite memory that has already been allocated so
you can just call it without checking if the desired quantity (like temperature gradient) is available
already.
Note that the memory allocation is not persistent. It will be freed automatically with the next iteration.
Example:
“Keep temporary solver memory from being freed” is set to “no”
Memory is allocated in DEFINE_ADJUST
It is highly unlikely that you can access the gradients in other DEFINE macros without allocating
the memory again because Fluent will allocate and free the temporary memory on the fly during
the iteration
This is shown in example 1 further down in this document
You can find more information about this testing procedure in solution #2039637 on the ANSYS
Customer Portal.
Like before, replace * with the variable you want to access, for example with the temperature gradient it
would look like:
Scalar_Reconstruction(domain, SV_T, -1, SV_T_RG, NULL);
Scalar_Derivatives(domain, SV_T, -1, SV_T_G, SV_T_RG, NULL);
You might have seen other forms for the temperature gradient in some UDFs used in tutorials or
downloaded from the 3rd party internet sources:
Scalar_Reconstruction(domain, SV_T, -1, SV_T_RG,
temperature_rgrad_accumulate);
Scalar_Derivatives(domain, SV_T, -1, SV_T_G, SV_T_RG,
temperature_deriv_accumulate);
The accumulate functions used in the above statements do not exist for all variables. In most cases the
result should be identical if replaced by NULL like in the generic example before.
Accumulate functions that do exist are:
temperature_rgrad_accumulate for temperature reconstruction gradients
temperature_deriv_accumulate for temperature gradients
Turb_Scalar_Rgrad_Accumulate for the specific dissipation rate reconstruction gradient
Vof_Deriv_Accumulate for the phase fraction gradient
For user-defined scalars you can use UDS_Derivatives(domain, n); with n = number of the
scalar in question instead of the two generic macros.
There is one scenario when this should not be done: if you want to post-process the gradients in Fluent
and therefore set /solve/set/expert as explained above.
The text command will make all gradients available to be used in UDF or standard post-processing. Now,
when you execute a UDF that allocates the memory itself this will not be a problem. As stated above the
memory will not be allocated a second time and calculating the gradients again does no harm. But when
you free the memory locations afterwards, they will gone until you either allocate them again or calculate
another iteration. Therefore it is not possible to access gradient macros in Fluent post-processing after
you free their memory with a UDF. To get the gradients back you would need to calculate another
iteration without calling the UDF.
Due to this behavior it is recommended not to use Free_Storage_Vars in your UDFs despite good
coding practices to free allocated memory when it is no longer required.
There is also a tutorial for horizontal film boiling available on the ANSYS Customer Portal that uses the
temperature and volume fraction (VOF) gradient macros. Just search the “Tutorials & Training Materials”
area for “Horizontal Film Boiling” without restriction of a certain Fluent version to locate it.
This example case contains several small UDFs to demonstrate how memory allocation and gradient
calculation work in general.
The example case is a generic tube with just a few cells and some zones. Note that this mesh is not
suited for a CFD simulation but for this demonstration purposes it should be sufficient.
1. Extract the contents of the archive to a new working folder
2. Start Fluent (serial, 3ddp) from that folder
3. Load the provided case file
4. Compile the C source file and load the library
5. Initialize the solution
First, you should be aware how to check if a certain variable is available in a given zone. This is just a
brief example, for more details look for solution #2039637 on the ANSYS Customer Portal.
Figure 3: Energy equation should not be active in the beginning of this example
Fluent reports that the energy equation is not active in all zones.
Then activate the energy equation and execute the UDF again.
Note that the output is identical to the previous output with disabled energy equation.
This time the UDF reports that the energy equation is active.
From this little example you should remember that just enabling a model does not make all variables
available immediately. You have to initialize the case or calculate at least one iteration to make the
variables available for your UDF.
Color description:
Comment
Compiler directive
Fluent DEFINE macro
Variable declaration
Fluent macros
Special Fluent arguments
Fluent loop macro
String
C statements
If you have access to parallel licenses, repeat the same steps in a parallel Fluent session.
Notice that some zones are reported to not have the energy equation enabled. This happens for threads
that do not contain any cells on a certain compute node. For example, take zone 31 that is marked in
Figure 7. It is empty on compute nodes 0 and 1 and therefore C_T could not be accessed there. But it is
possible to access the cells of the thread on compute nodes 2 and 3.
This is not a problem since Fluent handles all the loops correctly but you have to consider this when you
just want to check if a gradient is available somewhere.
With the energy equation active and the case initialized, check if the temperature gradient is available by
executing “chk_temp_grad”.
The first UDF reports that it is allocating the memory to access the temperature gradient and the second
one confirms this.
028 DEFINE_ON_DEMAND(chk_temp_grad)
029 {
030 #if !RP_HOST
031 Domain *d = Get_Domain(1);
032 Thread *t;
033
034 int grad_avail = -1;
035
036 thread_loop_c(t, d)
037 {
038 if (SV_ALLOCATED_P(t, SV_T_G)) {
039 grad_avail = 1;
040 break;
041 }
042 }
043
044 #if RP_NODE
045 grad_avail = PRF_GIHIGH1(grad_avail);
046 #endif
047
048 if (grad_avail == 1)
049 Message0("Memory for temperature gradient allocated.\n");
050 else
051 Message0("Memory for temperature gradient not available.\n");
052 #endif
053 }
Figure 10: Listing of UDF "chk_temp_grad"
The code of “chk_temp_grad” is similar to “test_eqn_cells” but the parallel characteristics noticed
earlier are considered.
You can use snippets of this code for your own UDFs because the procedure is always the same.
055 DEFINE_ON_DEMAND(alloc_temp_grad)
056 {
057 #if !RP_HOST
058 Domain *d = Get_Domain(1);
059
060 Message0("\nAllocating memory for C_T_G in the mixture domain.\n");
061 Alloc_Storage_Vars(d, SV_T_RG, SV_T_G, SV_NULL);
062 Message0("C_T_G is now available in all zones\n");
063 #endif
064 }
Figure 11: Listing of UDF "alloc_temp_grad_danger"
“chk_temp_grad” reports that the temperature gradients are available after executing
“alloc_temp_grad” but this UDF does nothing but allocating memory. It does not trigger an update of
the gradients.
Note that the UDF reports that the temperature gradient is available in any case. It does not double
check. The UDF executes normally even if the energy equation is disabled. Of course this would result in
a negative message by “chk_temp_grad” but not by “alloc_temp_grad”.
066 DEFINE_ON_DEMAND(acc_temp_grad)
067 {
068 #if !RP_HOST
069 Domain *d = Get_Domain(1);
070 Thread *t;
071 cell_t c;
072
073 real tmp_grad;
074
075 Message0("\nStarting thread loop...\n");
076 thread_loop_c(t, d)
077 {
078 Message0("Starting cell loop in thread %d, accessing C_T_G...\n",
THREAD_ID(t));
079 begin_c_loop_int(c, t)
080 {
081 tmp_grad = NV_MAG(C_T_G(c, t));
082 }
083 end_c_loop_int(c, t)
084 }
085 PRF_GSYNC();
086 Message0("C_T_G accessed in all cells\n");
087 #endif
088 }
Figure 13: Listing of UDR "acc_temp_grad"
As you can see from the output in Figure 12 and the listing in Figure 13 it is possible to access the
temperature gradient even without calculating the gradients.
090 DEFINE_ON_DEMAND(calc_temp_grad)
091 {
092 #if !RP_HOST
093 Domain *d = Get_Domain(1);
094
095 Message0("\nCalculating C_T_G in the mixture domain.\n");
096 T_derivatives(d);
097 Message0("C_T_G is available now.\n");
098 #endif
099 }
Figure 14: Listing of UDF "calc_temp_grad"
Usually line 96 is written right after line 61 in “alloc_temp_grad”. In this case this is separated into
different UDFs for demonstration purposes.
If you want to visualize the temperature gradients you can activate one UDM, execute
“acc_temp_grad_udm” and visualize UDM-0. This is not shown in this document.
Important: If you run “calc_temp_grad” without executing “acc_temp_grad” before, Fluent will report
a segmentation fault in serial and might even terminate the MPI process in parallel. This is also the case if
you run one or more iterations between executing “acc_temp_grad” and “calc_temp_grad”. There are
enhanced versions of both UDFs named “acc_temp_grad_secure” and “calc_temp_grad_secure”
included in the source file available in the attachment “2039716-example1.zip”. These enhanced versions
contain failsafe mechanisms to capture such errors without adding additional functionality. These failsafe
mechanisms were discussed before (see chapter Alloc_Storage_Vars above and solution #2039637 in
the ANSYS Customer Portal). Therefore the enhanced UDFs are not discussed in detail.
101 DEFINE_ON_DEMAND(free_temp_grad)
102 {
103 #if !RP_HOST
104 Domain *d = Get_Domain(1);
105
106 Message0("\nFreeing memory of C_T_G in the mixture domain.\n");
107 Free_Storage_Vars(d, SV_T_RG, SV_T_G, SV_NULL);
108 Message0("C_T_G is no longer available.\n");
109 #endif
110 }
Figure 15: Listing of UDF "free_temp_grad"
Lines 101 – 110: Main UDF body, code is executed on user request
Lines 103 – 109: Parallel compiler directives, code is executed in serial and on compute nodes but not on
the host process
Line 104: Variable declaration
Lines 106 + 108: Status messages
Line 107: Release the memory for temperature reconstruction gradients and temperature
gradients
Now invoke the text command /solve/set/expert and answer yes to “Keep temporary solver
memory from being freed?”
Figure 16: Fluent Text User Interface (TUI) with command to keep the temporary solver memory
Figure 17: Output of "chk_temp_grad" before and after the first iteration
6. Execute “free_temp_grad”
7. Show the same gradients again
a. Note that the gradients are still available
8. Execute “chk_temp_grad”
a. Note that freeing the memory by the UDF had no effect
Figure 19: Output of "free_temp_grad" and "chk_temp_grad" when TUI command is used
Note: Although this looks like the UDF to free the memory does not work if the text command is executed
before this is not always the case. A scenario where this fails is presented later.
Figure 20: Disable "Keep temporary solver memory from being freed?" with a text command
Figure 21: Magnitude of temperature gradient before (left) and after (right) "calc_temp_grad"
In Figure 21 you can see that it is really important to not only allocate the memory but to calculate the
gradients, too. You can only check if the memory location of the gradients is available but you cannot
check if the values stored at that location are up-to-date.
As mentioned earlier, there are cases when freeing the memory in a UDF produces problems during post-
processing. If you want to see such problems follow the steps:
1. Use /solve/set/expert to keep the temporary solver memory from being freed
2. Initialize the case
3. Display the contour plot of Derivatives > dT-dZ on the walls wall-in-1 to wall-in-5
4. Execute “alloc_temp_grad_secure”
5. Execute “calc_temp_grad_secure”
6. Execute “acc_temp_grad_secure_v2”
7. Execute “free_temp_grad”
8. Display the contour plot of dT-dZ on the same walls as before
a. Notice that some of the gradients have different values than before
9. Calculate another iteration to get them back
In this example you have seen how the different macros for gradient memory allocation and calculation
interact with each other. Feel free to experiment with different combinations to see the cases when Fluent
might even terminate a parallel process when memory allocation is not done properly.
Use the snippets from the provided UDFs and combine them in your own UDF to be sure that gradient
access works as intended.
All three macros Alloc_Storage_Vars(…), Scalar_Reconstruction(…) and Scalar_Derivatives(…)
have to be used together and in this exact order to get access to reconstruction gradient and gradient
macros.
Finally, keep in mind that freeing the memory afterwards can provoke a non-critical conflict with the
settings of the text command /solve/set/expert.
Memory allocation within this cell loop is not allowed. But you have access to certain gradients
nonetheless.
You can find all files that belong to this example in the attached archive “2039716-example-3.zip”.
Lines 14 – 16: Declaration of global variables used as error flags. Default value = error
Lines 22 – 31: Execute only if at least two UDMs are available
Line 24: Clear error flag for UDM
Lines 26 – 30: Execute only if temperature gradient is available
Line 28: Write the magnitude of the temperature gradient in the first UDM
Line 29: Clear error flag for temperature gradient
Both DEFINE_SOURCE UDFs are hooked as energy source. “heat_temp_grad” tries to access the
temperature gradient and reports an error if the gradient is not available. “heat_vof_grad” does the
same for the gradient of the volume fraction of the primary phase.
092 DEFINE_EXECUTE_AT_END(error_output)
093 {
094 #if RP_NODE
095 /* Reduce error flags on all compute nodes:
096 clear the flags if it is cleared somewhere */
097 PRF_GILOW3(vof_error, t_error, udm_error);
098 #endif
099
100 /* copy reduced error flags from compute node 0 to host for output */
101 node_to_host_int_3(vof_error, t_error, udm_error);
102
103 #if !RP_NODE
104 if (udm_error == 1)
105 Message("Define at least two UDMs for this test to work.\n");
106 if (vof_error == 1 && t_error != 1)
107 Message("VOF_G cannot be accessed from energy source; UDM 0:
Temperature gradient magnitude\n");
108 if (vof_error != 1 && t_error != 1)
109 Message("UDM 0: Temperature gradient magnitude; UDM 1: VOF
gradient magnitude\n");
110 if (vof_error != 1 && t_error == 1)
111 Message("T_G cannot be accessed from energy source; UDM 1: VOF
gradient magnitude\n");
112 if (vof_error == 1 && t_error == 1)
113 Message("T_G and VOF_G cannot be accessed from energy source\n");
114 vof_error = -1;
115 t_error = -1;
116 #endif
117 }
Figure 27: Listing of "error_output" UDF
“error_output” evaluates the value of the error flags after synchronizing them over all parallel
processes (lines 94 – 101). There are five possible messages printed by this UDF depending on which of
the gradients can be accessed. At the end it resets the error flags.
Obviously it is possible to access temperature gradients from a DEFINE_SOURCE that is hooked as energy
source. The solver requires the gradients during the calculation and stores them in a temporary memory
Now, you might have the idea to use another UDF to make the volume fraction gradient available.
DEFINE_ADJUST seems to be the best choice because it is executed at the beginning of each iteration.
Hook “allocate_vof” in the User-Defined Function Hooks panel and calculate another time step.
Although “allocate_vof” allocates the memory correctly, it is not available in “heat_vof_grad”. Fluent
clears the memory automatically.
The only possibility to keep the memory is to use the known text command.
Finally it is possible to access temperature and volume fraction gradients. Since the values have been
stored in a UDM you can also visualize them.
Two almost identical UDFs are included. Both calculate the temperature gradient in the normal direction
to all walls. “calc_wall_temp_grad_udm” stores this value in the first user-defined memory location.
“calc_wall_temp_grad_file” writes the gradient to a file. The second one is not discussed in this
document.
A third UDF is included for convenience to reset the first UDM to zero. Like “calc-
wall_temp_grad_file” it is not discussed in this document.
Figure 33: Contour plot of the temperature gradient in the normal direction to the walls of a tube
This example showed an application of accessing the temperature gradients in general purpose UDFs.
Remember to allocate the memory first, then trigger the calculation of the gradients.
You can free the memory for the unused reconstruction gradients if you like but this is not required and
could provoke unexpected results during post-processing as you have seen earlier.
It is always a good idea to check if prerequisites are met. In this case it is checked if the temperature is
available before even trying to allocate the memory for the gradients.
The UDF proposed here locates the cells where the gradient is larger than a user-defined threshold and
marks the cells by setting UDM 0 to 1.0. This will locate all cells adjacent to the free surface, including
droplets that are too small to be resolved properly.
Note that the mesh resolution of this demonstration case is far from a good CFD mesh.
1. Extract the archive “2039716-example-5.zip” that is attached to this solution to a new working
directory
2. Start Fluent 3ddp serial or parallel from that working directory
3. Load the case
4. Compile the source file and load the library
a. Keep the default name “libudf” of the UDF library
5. Execute the journal “images_setup.jou” to create some additional subdirectories and set some
general options to save images of this transient simulation
6. Run the simulation for a large number of time steps
a. Fluent will execute another journal periodically to save images into the subfolders created
earlier. This journal will execute the UDF automatically
b. Alternatively you can just patch the secondary phase to some cells and execute the UDF
to see how it works
Since this is a transient simulation the UDF has to be executed whenever the data is required. For this
demonstration it is used during post-processing, so it is called in a fixed interval by a journal. The UDM is
visualized directly and it is used to mark the cells.
Figure 36: Results of example 5 at two different time steps. Left: Isosurface of VOF = 0.9. Right: Marked cells by UDF
Note that this approach works quite well when using a sharp interface reconstruction. When using diffuse
interface reconstruction methods it is likely to locate the phase interface in a lot of cells which might not
be desired.
Figure 37: Results at the same time step with GeoReconstruct (top) and Compressive (bottom) interface
reconstruction schemes
Parallel considerations
There is not much to consider for parallel usage. Memory allocation and gradient calculation are done on
a domain level so they should be restricted to node processes with #if !RP_HOST … #endif. However,
the macros will do nothing on the host process so there is not much that you can do wrong.
Remember that the third approach is not supported by ANSYS which means that ANSYS can decline
working on support requests completely if the case in question depends on undocumented UDF macros.
Nevertheless using this approach is more robust for automation when done right.
Attachments
1. 2039716-example-1.zip
Files for the first example with general UDFs to learn the dependencies
2. 2039716-example-2.zip
Modified version of showgrad.c that is available in the Fluent Customization Manual
3. 2039716-example-3.zip
Files for the third example that covers how gradients can be accessed in model-specific UDFs
that are executed from a cell loop like DEFINE_SOURCE
4. 2039716-example-4.zip
Files for the usage example for temperature gradients to calculate the temperature gradient in the
direction normal to all walls
5. 2039716-example-5.zip
Files for the last example to locate the free surface of an open channel flow
6. 2039716-example-5-results.mp4
Animation of some of the results of the last example case
References
ANSYS Fluent Customization Manual, available for download from the ANSYS Customer Portal
at https://support.ansys.com under “Knowledge Resources > Online Documentation”
ANSYS Solution #2039637: “How to check if a Fluent solver variable can be accessed by User-
Defined Functions?” available for download from the ANSYS Customer Portal at
https://support.ansys.com under “Knowledge Resources > Solutions”
ANSYS Fluent Tutorial “Multiphase Flow Modeling using ANSYS FLUENT Tutorials : Horizontal
Film Boiling” available for download from the ANSYS Customer Portal at
https://support.ansys.com under “Knowledge Resources > Tutorials & Training Materials”