TAGGED: udf
-
-
May 18, 2026 at 9:47 pm
adib.aktab999
SubscriberHi everyone,
I am working on a simulation to analyze the effect of wind flow on coal combustion. My setup requires a non-equilibrium thermal model and includes oxidation reactions that generate \text{CO}_2, \text{CO}, and heat.
To achieve this, I implemented the governing equations via a User-Defined Function (UDF). I successfully compiled the UDF using Fluent's built-in compiler and hooked the functions to their respective zones/models perfectly.
However, when I run the simulation, I cannot see any effect from the UDF. The results look as if the UDF is not being executed at all.
Has anyone encountered a similar issue where a successfully compiled and hooked UDF does not influence the flow field or species generation? Any guidance on how to debug this or what I might be missing would be greatly appreciated.
Thank you in advance for your help!
-
May 19, 2026 at 7:55 am
Rob
Forum ModeratorWe (staff) won't be debugging code, but can give you some pointers. Assuming the code is correct (check for any warnings) what triggers the reaction? Ie do you need species/heat to start the reaction? In reality we need a spark or similar, and if you missed that in the initialisation & patch process you'll have a bunch of reactants happily flowing together out of the domain.
As an aside. If you're burning coal, how are you modelling the coal?
-
May 19, 2026 at 11:10 am
adib.aktab999
SubscriberI am modelling low-temperature spontaneous heating of a porous coal stockpile under wind-forced convection. The coal oxidation is represented using Arrhenius-type oxygen consumption, CO2/CO generation, and a volumetric heat source in the solid coal phase.
-
May 19, 2026 at 11:48 am
Rob
Forum ModeratorThe coal is a "solid" cell zone? Or are you using porous media? DEFINE_SOURCE or something else in the UDF?
-
May 19, 2026 at 12:10 pm
adib.aktab999
SubscriberHi Rob,
Thank you for the response. I am not modelling the coal as a simple solid cell zone only. I am modelling the coal stockpile as a porous fluid zone with non-equilibrium thermal model enabled.
My intention is to reproduce a low-temperature coal self-heating/spontaneous oxidation model similar to Zhang et al. The physical idea is that air flows through the porous coal pile, oxygen is consumed by coal oxidation, CO₂ and CO are generated, and the reaction heat is deposited into the coal solid phase.
My current Fluent setup is as follows.
1. Cell zones
I have two main domains:
- Farfield air domain
- Cell zone name:
farfield - Type: fluid
- Zone ID: 6
- This represents the surrounding wind/air region.
- Cell zone name:
- Coal stockpile domain
- Cell zone name:
stockpile - Type: fluid
- Zone ID: 7
- This is assigned as a porous fluid zone.
- The material assigned to this zone is the gas mixture used for species transport.
- Cell zone name:
After enabling the Non-Equilibrium Thermal Model inside the porous zone, Fluent automatically created a corresponding solid zone:
- Phantom/solid coal zone
- Cell zone name:
stockpile:016 - Type: solid
- Zone ID: 16
- This is selected under the non-equilibrium thermal model as the solid zone coupled to the porous fluid zone.
- Cell zone name:
So, the coal pile is not assigned as only a solid body. It is represented as a porous fluid region plus a coupled solid thermal zone through Fluent’s non-equilibrium porous model.
2. Models enabled
The following models are enabled:
- Energy equation: ON
- Species transport: ON
- Viscous model: RNG k-epsilon
- Multiphase: OFF
- Discrete phase: OFF
- Radiation: OFF
- Porous media: ON for the coal stockpile zone
- Non-equilibrium thermal model: ON for the stockpile porous zone
The reason for using the non-equilibrium thermal model is that I want separate gas and coal solid temperatures. The gas flows through the void spaces, while the coal matrix stores heat and receives heat generation from low-temperature oxidation.
3. Porous zone assignment
For the
stockpilefluid zone, I enabled:- Porous Zone
- Laminar Zone
- Source Terms
- Non-Equilibrium Thermal Model
The porous properties I assigned are:
Porosity = 0.2
Viscous resistance, Direction 1 = 1.2e8 1/m²
Viscous resistance, Direction 2 = 1.2e8 1/m²
Inertial resistance, Direction 1 = 0
Inertial resistance, Direction 2 = 0The viscous resistance was calculated from the Carman–Kozeny permeability relation using:
Porosity = 0.2
Coal particle diameter = 0.01 mThis gives approximately:
Permeability k ≈ 8.33e-9 m²
1/k ≈ 1.2e8 1/m²For the non-equilibrium thermal settings, I used:
Solid zone = stockpile:016
Interfacial area density = 2400 1/m
Heat transfer coefficient = 3 W/(m²·K)The interfacial area density is based on:
6(1 - porosity) / particle diameter
= 6(1 - 0.2) / 0.01
= 480 1/mHowever, I am currently testing higher values such as 2400 1/m to strengthen gas-solid heat exchange and check sensitivity.
4. Material assignment
For the porous fluid zone, I assigned the gas mixture material.
The mixture contains:
O2
CO2
CO
N2The intended species order in the UDF is:
0 = O2
1 = CO2
2 = CO
3 = N2N₂ is treated as the background/bulk gas species.
For the coal solid zone, I assigned coal-like thermal properties:
Coal density = 1400 kg/m³
Coal specific heat = 1300 J/(kg·K)
Coal thermal conductivity = 0.2 W/(m·K)5. Boundary conditions
The boundary conditions are:
Inlet
Boundary type: velocity inlet
Zone ID: 8The inlet wind velocity is applied through a UDF profile using a 1/7 power-law wind profile:
V(y) = Vref (y / Href)^(1/7)where:
Vref = 4 m/s
Href = 10 mThe inlet temperature is:
T = 293 KThe inlet species mass fractions are:
O2 = 0.23
CO2 = 0
CO = 0
N2 = 0.77Outlet
Boundary type: pressure outlet
Gauge pressure = 0 Pa
Zone ID: 9Walls
The bottom and top boundaries are assigned as walls. The bottom wall represents the ground, and the top wall is currently treated as a wall boundary following the paper-style simplified domain.
6. Initial condition and solution strategy
I am using a two-step solution method.
Step 1: Steady wind-flow solution
First, I solve the flow field without coal oxidation/heat generation. The goal is to obtain a stable wind field and pressure distribution around and inside the porous coal stockpile.
During this step, I keep the source terms either off or inactive.
Step 2: Transient self-heating simulation
Then I switch to transient simulation and activate the UDF source terms.
I patch/initialize the coal stockpile porous zone with:
O2 = 0.23
CO2 = 0
CO = 0
N2 = 0.77
Gas temperature = 293 K
Solid coal temperature = 293–303 KI have tested both 293 K and a slightly elevated coal initial temperature around 303 K to provide a small thermal trigger for the Arrhenius oxidation reaction.
The transient time step is currently:
Time step = 60 sThe reason is that low-temperature coal oxidation is a slow process and the paper also treats the heating process over days.
7. UDF source terms
I am using
DEFINE_SOURCEUDFs for oxygen consumption, CO₂ generation, CO generation, total mass source, and heat generation.The intended low-temperature oxidation reaction is:
Coal + O2 → CO2 + 0.1CO + heatThe reaction rate is Arrhenius-type:
r = (1 - ε) A [O2] exp(-Ea / RTs)where:
ε = 0.2
A = 1.8 1/s
Ea = 22000 J/mol
Heat of oxidation = 300 kJ/mol O2The UDF source terms are intended as follows:
UDF source Hook location o2_sinkstockpileporous fluid zone → source term for O2co2_sourcestockpileporous fluid zone → source term for CO2co_sourcestockpileporous fluid zone → source term for COmass_sourcestockpileporous fluid zone → source term for total masssolid_heatstockpile:016solid zone → energy sourcewind_inletinlet velocity profile The heat source is applied to the solid coal zone, not directly to the gas phase, because the coal oxidation heat should be stored in the coal matrix first and then exchanged with the gas through the non-equilibrium thermal coupling.
8. Current issue
The UDF compiles successfully and I can hook the functions in Fluent. However, when I run the simulation, I do not see the expected temperature rise or hotspot formation. The result looks almost the same as if the UDF source terms are not active.
UDF:#include "udf.h"/* ===== Physical constants (Zhang Table 1) ===== */#define A_PRE 1.8 /* Pre-exponential, 1/s */#define EA 22000.0 /* Activation energy, J/mol */#define R_UNIV 8.314 /* Gas constant, J/(mol K) */#define DELTAH 3.0e8 /* Heat of reaction, J/kmol O2 */#define EPS 0.2 /* Porosity *//* Molar masses, kg/mol */#define M_O2 0.032#define M_CO2 0.044#define M_CO 0.028/* Wind profile */#define V_REF 4.0#define H_REF 10.0/* Safety bounds */#define T_MIN 250.0#define T_MAX 1500.0#define RHO_MIN 0.1#define Y_FLOOR 0.0#define Y_CEIL 1.0#define Y_GROUND 1.0e-12/* Debug: cell ID to print from (limits console spam) */#define DEBUG_CELL 100/* ============================================================* Helper: volumetric reaction rate, kmol/m^3/s* Reads SOLID temperature via THREAD_SUB_THREAD.* Includes (1-eps) factor for solid volume fraction.* ============================================================ */real reaction_rate(cell_t c, Thread *t_fluid){Thread *t_solid;real T_coal, rho_gas, Y_O2, C_O2_kmol;t_solid = THREAD_SUB_THREAD(t_fluid, 1);if (t_solid == NULL)return 0.0;T_coal = C_T(c, t_solid);if (T_coal < T_MIN) T_coal = T_MIN;if (T_coal > T_MAX) T_coal = T_MAX;rho_gas = C_R(c, t_fluid);if (rho_gas < RHO_MIN) rho_gas = RHO_MIN;Y_O2 = C_YI(c, t_fluid, 0);if (Y_O2 < Y_FLOOR) Y_O2 = Y_FLOOR;if (Y_O2 > Y_CEIL) Y_O2 = Y_CEIL;C_O2_kmol = rho_gas * Y_O2 / M_O2 / 1000.0;return (1.0 - EPS) * A_PRE * C_O2_kmol * exp(-EA / (R_UNIV * T_coal));}/* ============================================================* Inlet wind profile: 1/7 power law* ============================================================ */DEFINE_PROFILE(wind_inlet, thread, position){face_t f;real x[ND_ND], y;begin_f_loop(f, thread){F_CENTROID(x, f, thread);y = x[1];if (y < Y_GROUND) y = Y_GROUND;F_PROFILE(f, thread, position) = V_REF * pow(y / H_REF, 1.0/7.0);}end_f_loop(f, thread)}/* ============================================================* O2 consumption (negative source)* ============================================================ */DEFINE_SOURCE(o2_sink, c, t, dS, eqn){real r = reaction_rate(c, t);real source_val = -r * M_O2 * 1000.0;dS[eqn] = 0.0;if (c == DEBUG_CELL)Message("DEBUG o2_sink: cell=%d, r=%g, source=%g kg/m3/s\n",c, r, source_val);return source_val;}/* ============================================================* CO2 production (positive source)* ============================================================ */DEFINE_SOURCE(co2_source, c, t, dS, eqn){real r = reaction_rate(c, t);real source_val = r * M_CO2 * 1000.0;dS[eqn] = 0.0;if (c == DEBUG_CELL)Message("DEBUG co2_source: cell=%d, r=%g, source=%g kg/m3/s\n",c, r, source_val);return source_val;}/* ============================================================* CO production (positive source, 0.1 stoichiometric ratio)* ============================================================ */DEFINE_SOURCE(co_source, c, t, dS, eqn){real r = reaction_rate(c, t);real source_val = 0.1 * r * M_CO * 1000.0;dS[eqn] = 0.0;if (c == DEBUG_CELL)Message("DEBUG co_source: cell=%d, r=%g, source=%g kg/m3/s\n",c, r, source_val);return source_val;}/* ============================================================* Heat generation on the SOLID coal phase* ============================================================ */DEFINE_SOURCE(solid_heat, c, t, dS, eqn){Thread *t_fluid;real r, source_val;t_fluid = THREAD_SUPER_THREAD(t);if (t_fluid == NULL)return 0.0;r = reaction_rate(c, t_fluid);source_val = r * DELTAH;dS[eqn] = 0.0;if (c == DEBUG_CELL)Message("DEBUG solid_heat: cell=%d, r=%g, source=%g W/m3\n",c, r, source_val);return source_val;} - Farfield air domain
-
May 19, 2026 at 12:32 pm
Rob
Forum ModeratorI'm not sure what your reaction_rate function is doing, but check it's actually calculating anything. You're also adding species but not mass to the domain (other than via molecular weight) so that may not help.
Finally, a dt of 60s is likely not going to run well. Whilst the chemistry is slow the transient resolution would need to be based on cell courant number which I'd expect to give a dt nearer 0.1-0.01s.
-
- You must be logged in to reply to this topic.
-
6435
-
1906
-
1457
-
1308
-
1022
© 2026 Copyright ANSYS, Inc. All rights reserved.