Вы находитесь на странице: 1из 39

____________________________________________________________________________________

How to access reconstruction gradient and


gradient macros in Fluent UDFs?
Problem/Description __________________________________________________________ 2
Introduction _________________________________________________________________ 3
When is memory allocation necessary? ___________________________________________ 5
How to allocate memory and make gradients available? _____________________________ 6
The official way to use gradient macros ________________________________________________ 6
The unofficial way to use gradient macros ______________________________________________ 6
Alloc_Storage_Vars _________________________________________________________________________ 6
Scalar_Reconstruction and Scalar_Derivatives ___________________________________________________ 7
Free_Storage_Vars _________________________________________________________________________ 8

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.

© 2015 ANSYS, Inc. All rights reserved.


Problem/Description
Gradient macros that can be used in ANSYS Fluent UDFs (User-Defined Functions) are described in the
Fluent Customization manual. But the manual does not go into much detail about when these macros are
available and what can be done to use them. This solution provides additional explanations and examples
about how and when these macros can be used.

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.

© 2015 ANSYS, Inc. All rights reserved.


Introduction
The Fluent Customization manual describes the gradient macros for pressure, velocity, temperature,
enthalpy, turbulence and species:
 Pressure C_P_G(c, t) / C_P_RG(c, t)
 Velocity C_U_G(c, t) / C_V_G(c, t) / C_W_G(c, t) / C_U_RG(c, t) /
C_V_RG(c, t) / C_W_RG(c, t)
 Temperature C_T_G(c, t) / C_T_RG(c, t)
 Enthalpy C_H_G(c, t) / C_H_RG(c, t)
 Turbulence C_NUT_G(c, t) / C_NUT_RG(c, t) / C_K_G(c, t) / C_K_RG(c, t) /
C_D_G(c, t) / C_D_RG(c, t) / C_O_G(c, t) / C_O_RG(c, t)
 Species C_YI_G(c, t, i) / C_YI_RG(c, t, i)
Text command required: (rpsetvar ‘species/save-gradients= #t)

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.

Figure 2: Number of parameters depend on active models, making automation difficult

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.

© 2015 ANSYS, Inc. All rights reserved.


If you do not follow these three steps on the UDF side you risk:
 Getting segmentation faults if you forget to set the text command correctly
 Access to undocumented gradient macros might be limited or not possible at all. One of those is
C_VOF_G(c, t) for the gradient of the volume fraction.

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

In the next chapters you learn how to minimize these risks.

© 2015 ANSYS, Inc. All rights reserved.


When is memory allocation necessary?
The gradients of pressure, the three velocity components and user-defined scalars should be available all
the time. If you need other physical quantities or want to access the reconstruction gradients you need to
allocate memory and trigger the calculation of the gradients.

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.

© 2015 ANSYS, Inc. All rights reserved.


How to allocate memory and make gradients available?
The official way to use gradient macros
To use the documented way use the text command
/solve/set/expert
and answer yes to the question "Keep temporary solver memory from being freed?". It is not
sufficient to just initialize the case to get access to the gradient macros. You need to run at least one
iteration after enabling this option. This has to be considered if you want to use gradient macros in UDFs
that are executed before an iteration to avoid segmentation faults. If you want to check if a variable can
be accessed by a UDF look into solution #2039637.

There are three downsides to this method:


1. Automation is not reliable for this specific text command. The number of parameters of
/solve/set/expert depends on the models used in your simulation. Therefore it makes sense
to look for an alternative for the text command and do everything on the UDF side.
2. You need to run one iteration which increases the effort for robust UDFs that execute before an
iteration or if the UDF is used for post-processing only
3. It might just not work for undocumented gradient macros

The unofficial way to use gradient macros


There are undocumented macros that allow you to allocate memory and (re-)calculate gradient and
reconstruction gradient macros on the fly. These are:
 Alloc_Storage_Vars(...)
 Scalar_Reconstruction(...)
 Scalar_Derivatives(...)
 Free_Storage_Vars(...)

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

© 2015 ANSYS, Inc. All rights reserved.


If you want to test if a gradient macro is available you can use SV_ALLOCATED_P(thread, SV_*).
Replace * with the quantity you want to test. For temperature and temperature gradient this would result
in lines such as:
 if (SV_ALLOCATED_P(thread, SV_T)) { /* Do something */ }
 if (SV_ALLOCATED_P(thread, SV_T_G)) { /* Do something */ }

You can find more information about this testing procedure in solution #2039637 on the ANSYS
Customer Portal.

Scalar_Reconstruction and Scalar_Derivatives


These macros (re-)calculate the gradients and store them in the memory allocated before. They have to
be called in the correct order. First Scalar_Reconstruction, second Scalar_Derivatives. You need
the reconstruction gradients in order to get the gradients even if you are not interested in using
reconstruction gradient macros.

Scalar_Reconstruction takes five arguments, Scalar_Derivatives six:


 Scalar_Reconstruction(domain, SV_*, -1, SV_*_RG, NULL);
 Scalar_Derivatives(domain, SV_*, -1, SV_*_G, SV_*_RG, NULL);

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

or simply the short form of the last two lines:


 T_derivatives(domain);

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.

© 2015 ANSYS, Inc. All rights reserved.


Free_Storage_Vars
Usually it is not required to free the memory. It will be freed automatically when calculating the next
iteration. However, it is good practice to free memory that has been allocated to avoid memory leaks. If
you want to follow that practice use one of the macros:
 Free memory of reconstruction gradients and gradients
o Free_Storage_Vars(domain, SV_*_RG, SV_*_G, SV_NULL);
 Free memory of the reconstruction gradients only. Gradients will still be available afterwards. This
is often used right after the calculation of the gradients when reconstruction gradients are not
required for the following operations.
o Free_Storage_Vars(domain, SV_*_RG, SV_NULL);
 Free memory of the gradients only. This is often used at the end of an UDF when the memory of
the reconstruction gradients have been freed after gradient calculation already.
 Free_Storage_Vars(domain, SV_*_G, SV_NULL);

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.

© 2015 ANSYS, Inc. All rights reserved.


Examples
Several examples are attached to this solution. In the following paragraphs you get a tutorial style
description of each of them

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.

Example 1: General Usage


All files related to this example case are packed together in the ZIP archive “2039716-example-1.zip”
attached to this solution on the ANSYS Customer Portal.

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.

Check under “Models” that the energy equation is not active.

Figure 3: Energy equation should not be active in the beginning of this example

Execute “testeqn” from “Define > User-Defined > Execute on Demand…”

Fluent reports that the energy equation is not active in all zones.

© 2015 ANSYS, Inc. All rights reserved.


Figure 4: Output of "testeqn::libudf" with disabled energy equation

Then activate the energy equation and execute the UDF again.
Note that the output is identical to the previous output with disabled energy equation.

Re-initialize the case and execute the UDF a third time.

Figure 5: Output of "testeqn::libudf" with active energy equation after re-initialization

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.

© 2015 ANSYS, Inc. All rights reserved.


The UDF is pretty simple:
001 /******************************************************/
002 /* */
003 /* Example UDF for ANSYS solution #2039716 */
004 /* General usage of gradient macros */
005 /* */
006 /* UDF provided without support */
007 /* */
008 /******************************************************/
009
010 #include "udf.h"
011
012 DEFINE_ON_DEMAND(test_eqn_cells)
013 {
014 #if !RP_HOST
015 Domain *d = Get_Domain(1);
016 Thread *t;
017 thread_loop_c(t, d)
018 {
019 if (!SV_ALLOCATED_P(t, SV_T)) {
020 Message("Energy Equation not active in zone %d on compute
node %d\n", THREAD_ID(t), myid);
021 } else {
022 Message("Energy Equation active in zone %d on compute node
%d\n", THREAD_ID(t), myid);
023 }
024 }
025 #endif /* !RP_HOST */
026 }
Figure 6: Listing of first example UDF "test_eqn"

Color description:
 Comment
 Compiler directive
 Fluent DEFINE macro
 Variable declaration
 Fluent macros
 Special Fluent arguments
 Fluent loop macro
 String
 C statements

This color coding will be used in all examples in this document.

© 2015 ANSYS, Inc. All rights reserved.


Explanation of the listing:
Lines 1 to 8: Introduction header as comment
Line 10: Include the standard UDF header file
Lines 12 to 26: Main UDF body, code is executed on user request
Lines 14 to 25: Restrict the code to be executed in serial and on compute nodes. It will not be executed
on the parallel host process
Lines 15 to 16: Variable declaration
Line 15: Get the domain pointer for the mixture domain
Lines 17 to 24: Loop over all cell threads that exist
Lines 19 to 23: Check if C_T could be accessed in the current thread and print a message about the
accessibility to the Fluent text interface (TUI) for each cell zone

If you have access to parallel licenses, repeat the same steps in a parallel Fluent session.

Figure 7: Output of "testeqn::libudf" 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”.

© 2015 ANSYS, Inc. All rights reserved.


Figure 8: Output of "chk_temp_grad::libudf" after initialization

It reports that the temperature gradient is not available.

Execute “alloc_temp_grad” followed by “chk_temp_grad”.

Figure 9: Output of "alloc_temp_grad_danger::libudf" followed by "chk_temp_grad::libudf"

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.

© 2015 ANSYS, Inc. All rights reserved.


Lines 28 – 53: Main UDF body, code is executed on user request
Lines 30 – 52: Parallel compiler directives, code is executed in serial and on compute nodes but not on
the host process
Lines 31 – 34: Variable declaration
Line 36: grad_avail is initialized with -1. It is used as flag to see if the temperature gradient is
available somewhere
Lines 36 to 42: Loop over all cell threads
Lines 38 to 41: Check if the temperature gradient is available in the current thread
Line 39: If the gradient is available in the current thread, set grad_avail to 1
Line 40: If the gradient is available in the current thread abort the loop. The memory has to be
allocated for all threads therefore it is sufficient to find a single thread where the
gradient is available
Lines 44 to 46: For parallel execution it is necessary to synchronize all compute nodes. If the gradient is
available on a single node that is enough to let all compute nodes know that the
temperature gradient can be accessed. Therefore the highest number of grad_avail is
distributed to all compute nodes
Lines 48 to 51: Print status messages for both cases to the Fluent TUI. It is printed only once for all
compute nodes together because grad_avail is identical everywhere

You can use snippets of this code for your own UDFs because the procedure is always the same.

Allocating memory takes even less code.

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"

Lines 55 – 64: Main UDF body, code is executed on user request


Lines 57 – 63: Parallel compiler directives, code is executed in serial and on compute nodes but not on
the host process
Line 58: Variable declaration
Line 60: Status message that memory allocation starts
Line 61: Allocate memory for temperature gradients and reconstruction gradients
Line 62: Status message that memory allocation is finished

“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”.

© 2015 ANSYS, Inc. All rights reserved.


Try to access the temperature gradients by executing “acc_temp_grad”.

Figure 12: Output of UDF "acc_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"

Lines 66 – 88: Main UDF body, code is executed on user request


Lines 68 – 87: Parallel compiler directives, code is executed in serial and on compute nodes but not on
the host process
Lines 69 – 73: Variable declaration
Line 73: tmp_grad is used as temporary storage only
Line 75: Status message that loop over all cell zones starts
Lines 76 – 84: Loop over all cell threads
Line 78: Status message about the current zone
Lines 79 – 83: Loop over all cells in the current thread

© 2015 ANSYS, Inc. All rights reserved.


Line 81: Store the magnitude of the temperature gradient in tmp_grad. This line does not make
much sense because tmp_grad will be overwritten for each cell. It is just used for
demonstration
Line 85: Wait until all compute nodes are finished with their loops
Line 86: Status message that zone loop is complete

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.

To calculate the gradients use “calc_temp_grad”.

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"

Lines 90 – 99: Main UDF body, code is executed on user request


Lines 92 – 98: Parallel compiler directives, code is executed in serial and on compute nodes but not on
the host process
Line 93: Variable declaration
Lines 95 + 97: Status messages
Line 96: Calculate temperature gradients and temperature reconstruction gradients

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.

The output of “acc_temp_grad” or “chk_temp_grad” do not change after executing


“calc_temp_grad”.

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.

© 2015 ANSYS, Inc. All rights reserved.


Before you continue, execute “free_temp_grad” to release the memory allocated before.

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

1. Initialize the case again


2. Execute “chk_temp_grad”
a. It will report that temperature gradients are not available
3. Calculate one iteration
4. Execute “chk_temp_grad” again
a. Now it reports that temperature gradients are available

Figure 17: Output of "chk_temp_grad" before and after the first iteration

5. Display the temperature gradients as contour plot on wall-in-1 to wall-in-5

© 2015 ANSYS, Inc. All rights reserved.


Figure 18: Contour plot of the temperature gradients on walls of the demonstration case

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.

© 2015 ANSYS, Inc. All rights reserved.


But first you should be aware when gradients are available for post-processing.

1. Disable the temporary memory storage again

Figure 20: Disable "Keep temporary solver memory from being freed?" with a text command

2. Initialize the case


3. Execute “alloc_temp_grad”
4. Execute “acc_temp_grad_udm”
5. Visualize UDM-0
6. Execute “calc_temp_grad”
7. Execute “acc_temp_grad_udm” again
8. Visualize UDM-0 again

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

© 2015 ANSYS, Inc. All rights reserved.


Figure 22: Temperature gradients before (left) and after (right) execution of all UDFs

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.

© 2015 ANSYS, Inc. All rights reserved.


Example 2: Check for available gradients
The manual provides an example UDF called “showgrad.c” to check which gradients are available. You
have also seen the principle in the previous example.
“showgrad.c” has some limitations regarding the output when run in parallel and for a case with multiple
cell zones. Therefore you can find a modified version as attachment to this solution under the name
“2039716-example-2.c”.
The code is not discussed in this document because you should know all the elements already from the
previous example.
Use the provided UDF if you just want to quickly check which gradient macros are available at the
moment.

© 2015 ANSYS, Inc. All rights reserved.


Example 3: Gradients in DEFINE_SOURCE
This artificial example uses several UDFs to demonstrate the behavior when accessing gradient macros
from DEFINE_SOURCE UDFs. Essentially all you learn in this example can be applied to different DEFINE
macros that are executed from within a cell loop.

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

1. Extract the contents of the archive in a new working directory


2. Start Fluent 3ddp serial from that working directory
3. Load the case
4. Compile the source file and load the library
a. Keep the default name “libudf” that the UDFs are hooked correctly with the provided
setup
5. Check the models, the Volume of Fluid multiphase model is active
6. Check the function hooks
a. Define > User-Defined > Function Hooks…

Figure 23: User-Defined Function Hooks for the third example

© 2015 ANSYS, Inc. All rights reserved.


i. An initialization UDF is used for your convenience to patch on of the two cell
zones with water during initialization. This UDF will not be discussed in this
document because it is off-topic
ii. A second UDF is executed at the end of each time step to print error messages.
In general it is not a good idea to print something to the text interface while
executing a cell loop
7. Check the Cell Zone Conditions
a. Cell Zone Conditions > fluid-1-sub > Mixture > Edit > Source Terms > Energy

Figure 24: Two UDFs are hooked as enrgy source terms

i. Two UDFs are hooked as energy source term

© 2015 ANSYS, Inc. All rights reserved.


011 #include "udf.h"
012
013 /* error flags - 1 = error, 0 = no error */
014 static int udm_error = -1;
015 static int vof_error = -1;
016 static int t_error = -1;
017
018 /* Hooked as energy source in mixture domain */
019 DEFINE_SOURCE(heat_temp_grad, c, t, dS, eqn)
020 {
021 /* Check if UDM is available */
022 if (N_UDM > 1) {
023 /* UDM available -> clear error flag for EXECUTE_AT_END */
024 udm_error = 0;
025 /* Check if C_T_G is available */
026 if (SV_ALLOCATED_P(t, SV_T_G)) {
027 /* store magnitude of gradient in UDM 0 */
028 C_UDMI(c, t, 0) = NV_MAG(C_T_G(c, t));
029 t_error = 0;
030 }
031 }
032
033 /* Energy source is zero in all cases */
034 dS[eqn] = 0.0;
035 return 0.0;
036 }
037
038 /* Hooked as energy source in mixture domain */
039 DEFINE_SOURCE(heat_vof_grad, c, t, dS, eqn)
040 {
041 /* Check if UDM is available */
042 if (N_UDM > 1) {
043 /* UDM available -> clear error flag for EXECUTE_AT_END */
044 udm_error = 0;
045 /* Check if C_VOF_G is available */
046 if (SV_ALLOCATED_P(THREAD_SUB_THREAD(t, 0), SV_VOF_G)) {
047 /* Store magnitude of gradient in UDM 1 */
048 C_UDMI(c, t, 1) = NV_MAG(C_VOF_G(c, THREAD_SUB_THREAD(t, 0)));
049 vof_error = 0;
050 }
051 }
052
053 /* Energy source is zero in all cases */
054 dS[eqn] = 0.0;
055 return 0.0;
056 }
Figure 25: DEFINE_SOURCE UDFs hooked as energy source

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

© 2015 ANSYS, Inc. All rights reserved.


Lines 34 – 35: Set return values to zero that no energy source is applied
Lines 39 – 56: Same as before (19 – 36) but with volume fraction instead of temperature

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.

Initialize the case and run one time step.


The “error_output” UDF reports that the VOF gradient cannot be accessed but the temperature
gradient is available.

Figure 26: Output of the "error_output" UDF

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

© 2015 ANSYS, Inc. All rights reserved.


block. This can be accessed from the DEFINE_SOURCE. But as soon as this data is no longer required it is
removed and therefore it is not possible to access the gradients for the volume fraction from an energy
source term.

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.

Figure 28: "allocate_vof" hooked at Adjust function hooks

Figure 29: Output with hooked "allocate_vof" DEFINE_ADJUST UDF

© 2015 ANSYS, Inc. All rights reserved.


121 DEFINE_ADJUST(allocate_vof, d)
122 {
123 #if !RP_HOST
124 Domain *sd1, *sd2;
125 sd1 = DOMAIN_SUB_DOMAIN(d, 0);
126 sd2 = DOMAIN_SUB_DOMAIN(d, 1);
127 Alloc_Storage_Vars(sd1, SV_VOF_RG, SV_VOF_R, SV_NULL);
128 Scalar_Reconstruction(sd1, SV_VOF, -1, SV_VOF_RG, NULL);
129 Scalar_Derivatives(sd1, SV_VOF, -1, SV_VOF_G, SV_VOF_RG,
Vof_Deriv_Accumulate);
130 Alloc_Storage_Vars(sd2, SV_VOF_RG, SV_VOF_R, SV_NULL);
131 Scalar_Reconstruction(sd2, SV_VOF, -1, SV_VOF_RG, NULL);
132 Scalar_Derivatives(sd2, SV_VOF, -1, SV_VOF_G, SV_VOF_RG,
Vof_Deriv_Accumulate);
133 #endif
134 }
Figure 30: Listing of "allocate_vof" UDF

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.

1. Remove “allocate_vof” from the function hooks panel


2. Type the text command /solve/set/expert and answer yes to “Keep temporary solver
memory from being freed?”
3. Run a third time step

Figure 31: Output after using the text command /solve/set/expert

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.

Figure 32: Visualization of temperature (left) and vof (right) gradients

© 2015 ANSYS, Inc. All rights reserved.


Although allocating memory within a UDF is a good idea for general purpose DEFINE macros it is not
possible for DEFINE macros that are executed by Fluent during a cell loop. In such cases you have
access to the gradients that are required by the solver. For a DEFINE_SOURCE it depends on where the
UDF is hooked. If it is hooked as energy source you have access to temperature gradients without
additional effort. However, if you need access to gradients of other quantities you have to use the text
command /solve/set/expert to keep the temporary solver memory.

© 2015 ANSYS, Inc. All rights reserved.


Example 4: Temperature gradients
This example uses another tube to show how to access gradients in general purpose DEFINE macros. All
files are attached to the solution in one archive “2039716-example-4.zip”.

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.

1. Extract the contents of the attached archive “2039716-example-4.zip” to a new working


directory
2. Start Fluent 3ddp serial or parallel from that directory
3. Read the case
4. Compile the source file and load the library
5. Calculate some iterations
6. Execute the UDF “calc_wall_temp_grad_udm” from Define > User-Defined > Execute on
Demand…
7. Use contour plots to visualize the temperature gradient normal to the different walls

Figure 33: Contour plot of the temperature gradient in the normal direction to the walls of a tube

© 2015 ANSYS, Inc. All rights reserved.


012 #include "udf.h"
013
016 DEFINE_ON_DEMAND(calc_wall_temp_grad_udm)
017 {
018 #if !RP_HOST
019 Domain *d = Get_Domain(1); /* Mixture domain */
020 Thread *t, *tf; /* Face and cell threads */
021 face_t f;
022 cell_t c0;
023
024 int temp_avail = -1;
025
026 real cell_coordinates[ND_ND], face_coordinates[ND_ND],
distance[ND_ND], A[ND_ND], p0[ND_ND];
027 real alpha0, beta0;
028
029 /* Check if UDM 0 is available */
030 if (N_UDM < 1) {
031 /* Abort execution due to insufficient UDMs */
032 Message0("Error: At least one user-defined memory location
required.\n");
033 return;
034 }
035
036 /* Check if energy equation is enabled */
037 thread_loop_c(t, d)
038 {
039 if (NNULLP(THREAD_STORAGE(t, SV_T))) {
040 temp_avail = 1;
041 break;
042 }
043 }
044
045 /* Sync all compute nodes */
046 #if RP_NODE
047 temp_avail = PRF_GIHIGH1(temp_avail);
048 #endif
049
050 if (temp_avail < 1) {
051 /* Abort execution if temperature cannot be accessed in all
threads on all nodes */
052 Message0("Error: Energy equation has to be active.\n");
053 return;
054 }
055
/* Continued on next page */

© 2015 ANSYS, Inc. All rights reserved.


/* Continuation from previous page */
055
056 /* Allocate memory for temperature gradients */
057 Alloc_Storage_Vars(d, SV_T_RG, SV_T_G, SV_NULL);
058 /* Calculate temperature gradients */
059 T_derivatives(d);
060 /* Free memory for reconstruction gradient - this is NOT required */
061 Free_Storage_Vars(d, SV_T_RG, SV_NULL);
062
063 /* Loop over all face threads */
064 thread_loop_f(tf, d)
065 {
066 /* Continue only if the current thread is of type wall */
067 if (THREAD_TYPE(tf) == THREAD_F_WALL) {
068 /* Loop over all faces of the wall */
069 begin_f_loop(f, tf)
070 {
071 /* Make sure that only faces are accessed that are associated
with the compute node */
072 if (PRINCIPAL_FACE_P(f, tf)){
073 t = THREAD_T0(tf); /* Adjacent cell thread */
074 c0 = F_C0(f, tf); /* Identify adjacent cell */
075 C_CENTROID(cell_coordinates, c0, t);/*get cell coordinates*/
076 F_CENTROID(face_coordinates, f, tf);/*get face coordinates*/
077 NV_VV(distance,=,face_coordinates,-,cell_coordinates);
/* calculate distance between cell and face center */
078 F_AREA(A, f, tf); /* get face normal vector */
079 alpha0 = NV_DOT(A, A)/NV_DOT(A, distance);
080 NV_VS_VS(p0,=,A,/,alpha0,-,distance,*,1);
081 beta0 = NV_DOT(p0, C_T_G(c0, t));
082 C_UDMI(c0, t, 0) = (F_T(f, tf) - C_T(c0, t) + beta0) *
alpha0/NV_MAG(A); /* Gradient normal to surface */
083 }
084 }
085 end_f_loop(f ,tf)
086 }
087 }
088 /* Free memory for gradient - this is NOT required */
089 Free_Storage_Vars(d, SV_T_G, SV_NULL);
090 Message0("Temperature gradients normal to all walls available in
UDM-0.\n");
091 #endif /* !RP_HOST */
092 }
Figure 34: Listing of "calc_wall_temp_grad_udm"

Lines 19 – 27: Variable declarations


Line 24: temp_avail is used as error flag in case the temperature cannot be accessed
Lines 30 – 34: Check if at least UDM 0 is available and abort UDF with an error message if not
Lines 37 – 43: Loop over all cell threads to check if the energy equation is available. The loop stops as
soon as the first thread is found where this is true
Lines 46 – 48: Synchronize temp_avail over all compute nodes
Lines 50 – 54: Abort if temperature is not available

© 2015 ANSYS, Inc. All rights reserved.


Lines 57 – 61: Allocate memory for temperature gradients, calculate the gradients and remove the
reconstruction gradients from memory because they are not required
Lines 64 – 87: Loop over all face threads
Lines 67 – 86: Check if the current thread is a wall thread. Nothing is done on the current thread if it is
not a wall thread
Lines 69 – 87: Loop over all faces in the current thread
Line 72: Continue only if the current face is native to the compute node it is accessed from
Lines 73 – 82: Calculate the gradient normal to the surface and store It in the first UDM of the adjacent
cell
Line 89: Free the temporary solver memory

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.

© 2015 ANSYS, Inc. All rights reserved.


Example 5: Locate free surface
In this example you learn how to access gradients for the volume fraction. The example model uses the
Volume of Fluid model but it works in the same way for Mixture and Eulerian multiphase models.

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

© 2015 ANSYS, Inc. All rights reserved.


10 #include "udf.h"
11
12 /* Absolute value of magnitude of gradient of volume fraction to detect
phase interface */
13 #define VOF_GRAD_THRESHOLD 0.1
14 /* ID taken from phase panel in Fluent - has to be larger than 1 */
15 #define PHASE_ID 2
16
17 DEFINE_ON_DEMAND(calc_free_surface_level)
18 {
19 #if !RP_HOST
20 Domain *d = Get_Domain(PHASE_ID); /* phase domain */
21 Thread *t; /* cell thread */
22 cell_t c; /* cell index */
23
24 int vof_avail = -1;/*VOF flag == 1 -> C_VOF is available somewhere*/
25 int cell_count = 0; /* Number of cells that will be marked */
26
27 /* Check if UDM 0 is available */
28 if (N_UDM < 1) {
29 /* Abort due to insufficient number of UDMs */
30 Message0("Error: At least one user-defined memory location
required.\n");
31 return;
32 }
33
34 /* Check if VOF is available somewhere */
35 /* Loop over all cell threads */
36 thread_loop_c(t, d)
37 {
38 /* Check if VOF is available */
39 if (SV_ALLOCATED_P(t, SV_VOF)) {
40 vof_avail = 1;
41 break; /* Abort loop after the first zone with available VOF
macro is found */
42 }
43 }
44
45 #if RP_NODE
46 /* Synchronize all compute nodes. Let all compute nodes know if
VOF macros are available somewhere */
47 vof_avail = PRF_GIHIGH1(vof_avail);
48 #endif
49
50 /* Abort if VOF macros cannot be accessed in all threads on all
nodes */
51 if (vof_avail < 1) {
52 Message0("Error: Not a multiphase simulation or incorrect phase ID
(domain).\n");
53 return;
54 }

© 2015 ANSYS, Inc. All rights reserved.


56 Message0("Allocating memory...\n"); /* Information output, useful
for debugging, not required */
57 /* Allocate memory for VOF gradients */
58 Alloc_Storage_Vars(d, SV_VOF_RG, SV_VOF_G, SV_NULL);
59
60 Message0("Triggering gradient update..."); /* Information output,
useful for debugging, not required */
61 /* Trigger VOF gradient update */
62 Scalar_Reconstruction(d, SV_VOF, -1, SV_VOF_RG, NULL);
63 Scalar_Derivatives(d, SV_VOF, -1, SV_VOF_G, SV_VOF_RG,
Vof_Deriv_Accumulate);
64
65 Message0("Starting thread loop...\n"); /* Information output, useful
for debugging, not required */
66 /* Loop over all cell threads */
67 thread_loop_c(t, d)
68 {
69 /* Continue only if the current thread is of type fluid AND VOF
macros are available */
70 if (FLUID_THREAD_P(t) && SV_ALLOCATED_P(t, SV_VOF_G)){
71 Message0("Accessing zone %d...\n", THREAD_ID(t));
/* Information output, useful for debugging, not required */
72 /* Loop over all cells */
73 begin_c_loop_int(c, t)
74 {
75 /* Mark cell if VOF gradient is larger than threshold */
76 if (NV_MAG(C_VOF_G(c,t)) > VOF_GRAD_THRESHOLD) {
77 C_UDMI(c, THREAD_SUPER_THREAD(t), 0) = 1.0;
/* UDMs may only be accessed from the mixture
thread, never from a phase thread */
78 cell_count++; /* count marked cells */
79 } else {
80 /* unmark cell below threshold */
81 C_UDMI(c, THREAD_SUPER_THREAD(t), 0) = 0.0;
82 }
83 }
84 end_c_loop_int(c ,t)
85 } else {
86 Message0("Warning: Zone %d is either not a fluid thread or
C_VOF_G is not available.\n", THREAD_ID(t));
87 }
88 }
89 #if RP_NODE
90 cell_count = PRF_GISUM1(cell_count); /* Get global sum of all
marked cells on all compute nodes */
91 #endif
92 Message0("\nRun complete, %d cells surrounding the free surface
level are marked in UDM 0.\n\n", cell_count);
93 Free_Storage_Vars(d, SV_VOF_G, SV_VOF_RG, SV_NULL);
/* Free memory, not required */
94 #endif /* !RP_HOST */
95 }
Figure 35: Listing of "calc_free_surface_level"

© 2015 ANSYS, Inc. All rights reserved.


Line 13: Threshold value for the volume fraction gradient magnitude that is used to mark
the cells
Line 15: Phase ID of the primary or secondary phase taken from Fluent
Lines 20 – 25: Variable declarations
Line 24: vof_avail is used as error flag in case the volume fraction is not available
Line 25: cell_count stores the number of cells detected by the UDF to be part of the
free surface level
Lines 28 – 32: Chek if UDM 0 is available and abort if not
Lines 36 – 54: Check if the volume fraction is available and abort if not. Details about the
implemented method are explained in previous examples
Lines 56, 60, 65 and 92: Status output to Fluent text interface
Lines 58 – 63: Allocate memory and calculate VOF gradients
Lines 67 – 88: Loop over all cell threads
Lines 70 – 87: Check if the current thread is a fluid thread and the volume fraction is available.
A message is printed if one of both conditions return false and the loop
continues with the next cell thread
Lines 73 – 84: Loop over all cells of the current thread and compute node
Lines 73 – 82: Check if the magnitude of the VOF gradient is larger than the threshold defined
in line 13.
Line 77: Set UDM 0 to 1 if condition is met. Note that UDMs have to be used in the
mixture thread, never in phase threads
Line 78: Count all marked cells
Line 81: Set UDM 0 to 0 if condition is not met
Lines 89 – 91: Calculate the sum of all marked cells over all parallel compute nodes
Line 93: Release the memory used for the volume fraction gradients and reconstruction
gradients

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

© 2015 ANSYS, Inc. All rights reserved.


You can find an animation of the results attached to the solution as “2039716-example-5-
results.avi”.

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

© 2015 ANSYS, Inc. All rights reserved.


Multiphase considerations
For multiphase cases you have to make sure that you pass along the correct domain because not all
quantities will be available for all phases. Some might be restricted to the mixture domain, some to phase
domains. This depends on the multiphase model you use.
For example, for a VOF simulation C_VOF_G has to be allocated from a phase domain. All other gradients
from the mixture domain. For the Eulerian model all gradients except the pressure have to be allocated
from phase domains.
It is a good idea to check if the desired quantity and/or its gradient is available before accessing the
gradient to prevent access errors.

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.

© 2015 ANSYS, Inc. All rights reserved.


Summary
There are three possibilities to access gradients in UDFs:
 Some gradients can be accessed from DEFINE macros that are executed from within a cell loop
without additional effort. Which variable you can access depends on the place where the DEFINE
macro is hooked and when at which solver stage it is accessed.
 Use the text command /solve/set/expert to prevent freeing the temporary solver memory.
Afterwards you have to run at least one iteration that you can access the gradients from UDF or
the Fluent text or graphical interfaces.
Unfortunately this cannot be automated easily because this text command has a variable number
of parameters that depend on the active models.
 Allocate the memory in the UDF, trigger the update of the gradients and access the gradients.
This is usually done in general purpose DEFINE macros like DEFINE_ON_DEMAND, DEFINE_ADJUST
or DEFINE_EXECUTE_AT_END. Three macros are required for the manual memory allocation:
o Alloc_Storage_Vars(domain, SV_*_RG, SV_*_G, SV_NULL);
o Scalar_Reconstruction(domain, SV_*, -1, SV_*_RG, NULL);
o Scalar_Derivatives(domain, SV_*, -1, SV_*_G, SV_*_RG, NULL);

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”

© 2015 ANSYS, Inc. All rights reserved.

Вам также может понравиться