FLUENT 6.2 - air handler boundary condition (recirculation with multiphase and species)


In an agent dispersion simulation, it may be necessary to implement recirculation boundary conditions that handle different species and/or different phases separately.


This UDF is for recirculation BCs with air exchange and filtering of species and secondary phase. A square wave pulse of both species and secondary phase is introduced simultaneously into the domain from an inlet during a given release time. A define_at_end UDF is used to compute recirculation quantities from a given outlet, as well as to store time integrals of species and secondary phase in two UDMs. Two define_profile UDFs define the species mass fraction and the volume fraction of secondary phase at the inlet. The UDF could be extended to increase the complexity of the air handling mechanism. The UDF is also a clarifying example for multiphase multispecies UDFs in general. The UDF is parallelized.

UDF code follows:


/* air handler UDFs for recirculation of species and phases from outlets to inlets in a
general multiphase multispecies problem. implemented for recirculation of one species and
one secondary phase from one outlet, after a simultaneous square wave pulse of each at the
inlet. primary phase is mixture containing recirculating species. designated secondary phase
recirculates also. udfs are parallelized. udfs also track enable 2 user defined memory locations for storage.

by Federico Montanari 11/10/05 feedback to fm@fluent.com */

#include "udf.h"
#include "unsteady.h"

#define id_outlet 4 /* from bc panel */

#define total_mfr_pulse_sp 1.0 /* desired amplitude of inlet pulse kg/s for species carrier gas*/
#define total_mfr_pulse_ph 0.1 /* desired amplitude of inlet pulse kg/s for phase dust */

#define start_time_pulse 120.0 /* desired start time of pulse s */
#define end_time_pulse 130.0 /* desired end time of pulse s */

#define flow_split_factor 0.75 /* fraction of air recirculated from air handler */
#define filter_efficiency 0.3 /* filtered fraction of species in air handler */

real sum_sp = 0.0; /* store mass flow rate of species at outlet */
real sum_ph = 0.0; /* store mass flow rate of secondary phase at outlet */


DEFINE_EXECUTE_AT_END(execute_at_end)
{
/* the layout of user defined functions (DEFINE udfs) that operate on a multiphase problem
will depend on the arguments that are passed to each udf. an define_execute_at_end
udf is a worse case scenario in the sense that it is not passed any argument.
therefore all information on the structure of the data for the flowfield has to
be retrieved from multiphase-specific macros */

Domain *mixture_domain;
mixture_domain = Get_Domain(1); /* in fluent 6.2 and previous, returns domain
pointer for mixture domain if multiphase, or for the single fluid domain if
no multiphase */

int phase_domain_index = 1; /* identifier for recirculating phase. phase_domain_index is an index of
subdomain pointers that starts with 0 for the primary phase and is
incremented by one for each secondary phase, used as exemplified below */

Domain *subdomain_secondary_phase = DOMAIN_SUB_DOMAIN(mixture_domain,phase_domain_index);
/* returns the phase pointer for the given domain pointer mixture_domain and phase_domain_index
(here the DUST) */
Domain *subdomain_primary_phase = DOMAIN_SUB_DOMAIN(mixture_domain,0);
/* returns the phase pointer for the given domain pointer mixture_domain
and phase_domain_index 0 (here the CARRIER GAS) */

Thread *mixture_thread = Lookup_Thread(mixture_domain, id_outlet);
/* mixture-level thread pointer for id_outlet (here DUST, CG AND AIR) */
Thread *subthread_secondary_phase = THREAD_SUB_THREAD(mixture_thread,phase_domain_index);
/* phase level thread for id_outlet and phase pointed to by phase_domain_index (here DUST) */
Thread *subthread_primary_phase = THREAD_SUB_THREAD(mixture_thread,0);
/* phase level thread for id_outlet and primary phase (here CARRIER GAS + AIR) */

int zone_ID = THREAD_ID(subthread_secondary_phase); /* to verify that the secondary phase (here DUST)
thread retrieved does correspond to the desired zone
(id displayed in the bc panel) */
int domain_id_sec = DOMAIN_ID(subdomain_secondary_phase);
/* to verify that the subdomain corresponds to the desired phase (phase id displayed in
the phases panel) (here DUST) */
int domain_id_prim = DOMAIN_ID(subdomain_primary_phase);
/* to verify that the subdomain corresponds to the primary phase (phase id displayed in
the phases panel) (here CARRIER GAS AND AIR) */
face_t f; /* face index to refer to faces visited in this DEFINE udf */
cell_t c; /* cell index to refer to cells visited in this DEFINE udf */

Thread **pt; /* pt is array of pointers to phase-level threads (subthreads).
pt[i] is a pointer to $i$th phase-level thread, where i is the phase_domain_index.
pt[0] is same as THREAD_SUB_THREAD(mixture_thread,0) */

Thread *ct; /* cell thread to refer to cells visited in this DEFINE udf */

real flux;

sum_sp = 0.0;
sum_ph = 0.0;

#if !RP_HOST
begin_f_loop(f,subthread_primary_phase)
{
if PRINCIPAL_FACE_P(f,subthread_primary_phase) /* in parallel, accumulate area and flux only on the principal node */
{
flux = F_FLUX(f,subthread_primary_phase); /* mass flow rate of primary phase (here CARRIER GAS AND AIR) */
sum_sp += flux * F_YI(f,subthread_primary_phase,0); /* sum_sp calculates the mass flow rate of species 0 in the
primary phase. 0th species refers to CARRIER GAS.
normally, all face normals at a boundary point outside
the computational domain, and f_flux returns positive
numbers for fluxes exiting the computational domain */

flux = F_FLUX(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(subthread_primary_phase),phase_domain_index));
/* mass flow rate of secondary phase (here DUST) */
sum_ph += flux; /* sum_ph calculates the volume averaged mass flow rate of the secondary
phase chosen. normally, all face normals at a boundary point outside the
computational domain, and f_flux returns positive numbers for fluxes exiting
the computational domain */
}
}
end_f_loop(f,subthread_primary_phase)
#endif /* !RP_HOST */

sum_sp = PRF_GRSUM1(sum_sp); /* in parallel, perform global reduction of summations of mass flow rate of species */
sum_ph = PRF_GRSUM1(sum_ph); /* and secondary phase */

node_to_host_real_2(sum_sp,sum_ph);

#if !RP_NODE
Message("Requested outlet zone id: %it accessed outlet zone id: %in ", id_outlet, zone_ID);
Message("Accessed primary phase id: %in ", domain_id_prim);
Message("Accessed secondary phase id: %in ", domain_id_sec);
Message("Integrated outlet mass flow of species: %en", sum_sp);
Message("Integrated outlet mass flow of secondary phase: %en", sum_ph);
#endif /* !RP_NODE */

/* The following steps integrate mass of both species
and secondary phase as a function of time and store in udm */

#if !RP_HOST
mp_thread_loop_c (ct,mixture_domain,pt)
{
begin_c_loop_int (c,ct)
{
if(CURRENT_TIME < start_time_pulse)
{
C_UDMI(c,ct,0) = 0.0;
C_UDMI(c,ct,1) = 0.0;
}
else
{
C_UDMI(c,ct,0) += CURRENT_TIMESTEP * C_R(c,pt[0]) * C_YI(c,pt[0],0) * C_VOLUME(c,pt[0]);
/* density of primary phase * mass fraction of species * volume of cell = mass of species in cell */

C_UDMI(c,ct,1) += CURRENT_TIMESTEP * C_R(c,pt[phase_domain_index]) *
C_VOF(c,pt[phase_domain_index]) * C_VOLUME(c,ct);
/* density of secondary phase * volume fraction of secondary phase * volume of cell = mass of
secondary phase in cell */
}
}
end_c_loop_int (c,ct)
}
#endif /* !RP_HOST */

}


DEFINE_PROFILE(sp_mfr_profile,t,i)
{
/* this udf to be hooked to mass fraction of recirculating species at inlet.
in the case of a define profile udf, the udf is already passed the appropriate
thread (t) and variable identifier (i) so that it is sufficient to provide the
actual value that must be used for that variable, as a function of spatial position
and/or time if needed */

real sp_flow_tot, ph_mfr;
face_t f;

sp_flow_tot = flow_split_factor * sum_sp;

if(CURRENT_TIME > start_time_pulse && CURRENT_TIME < end_time_pulse)
{
sp_flow_tot += total_mfr_pulse_sp;
}

ph_mfr = 0.0;
begin_f_loop(f,t)
{
if PRINCIPAL_FACE_P(f,t) /* in parallel, accumulate area and flux only on the principal node */
{
ph_mfr += F_FLUX(f,t); /* total mass flow rate of primary phase through the inlet */
}
}
end_f_loop(f,t)

ph_mfr = PRF_GRSUM1(ph_mfr); /* in parallel, perform global reduction of summations for mass flow rate of primary phase */

if(ph_mfr == 0.0)
{
ph_mfr = - 1.0;
Message0("Found zero inlet mass flow rate of primary phase n");
}

begin_f_loop(f,t)
{
F_PROFILE(f,t,i) = - sp_flow_tot/ph_mfr; /* profile is positive mass fraction. flow is prescribed
in the z direction. */
}
end_f_loop(f,t)

Message0("Imposed total mass flow of species at inlet: %en",sp_flow_tot);
}


DEFINE_PROFILE(ph_mfr_profile,t,i)
{
/* this udf to be hooked to volume fraction of recirculating phase at inlet.
in the case of a define profile udf, the udf
is already passed the appropriate thread (t) and variable identifier
(i) so that it is sufficient to provide the actual value that must be used
for that variable, as a function of spatial position and/or time if needed */

Domain *mixture_domain;
mixture_domain = Get_Domain(1); /* in fluent 6.2 and previous, returns domain
pointer for mixture domain if multiphase, or for the single fluid domain if
no multiphase */

real ph_flow_tot, ph1_mfr;
face_t f;

ph_flow_tot = flow_split_factor * (1 - filter_efficiency) * sum_ph;

if(CURRENT_TIME > start_time_pulse && CURRENT_TIME < end_time_pulse)
{
ph_flow_tot += total_mfr_pulse_ph;

if(ph_flow_tot == 0.0)
{
ph_flow_tot = 1.0e-15;
Message0("Found zero prescribed inlet mass flow rate of secondary phase n");
}
}

ph1_mfr = 0.0;
begin_f_loop(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0))
{
if PRINCIPAL_FACE_P(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0)) /* in parallel, accumulate area and flux
only on the principal node */
{
ph1_mfr += F_FLUX(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0)); /* total mass flow rate of primary phase
through the inlet */
}
}
end_f_loop(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0))

ph1_mfr = PRF_GRSUM1(ph1_mfr); /* in parallel, perform global reduction of summations for mass flow rate of primary phase */

if(ph1_mfr == 0.0)
{
ph1_mfr = - 1.0;
Message0("Found zero inlet mass flow rate of primary phase n");
}

begin_f_loop(f,t)
{
F_PROFILE(f,t,i) = (ph_flow_tot/C_R(F_C0(f,t),THREAD_T0(t)))/
(- ph1_mfr/C_R(F_C0(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0)),THREAD_T0(THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0))) +
ph_flow_tot/C_R(F_C0(f,t),THREAD_T0(t)));
/* profile is positive volume fraction, flow in z direction. A[2]/(A_tot[2]) ratio of facet flow area to
total face flow area. ph_flow_tot/C_R(F_C0(f,t),THREAD_T0(t)) is volumetric flow rate of dust based on
density of secondary phase at neighboring cell,
(ph1_mfr/C_R(F_C0(f,THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0)),THREAD_T0(THREAD_SUB_THREAD(THREAD_SUPER_THREAD(t),0))) +
ph_flow_tot/C_R(F_C0(f,t),THREAD_T0(t)))/ is volumetric flow rate of entire flow (both phases) based on density
of each phase at neighboring cell */
}
end_f_loop(f,t)

Message0("Imposed total mass flow of secondary phase: %en",ph_flow_tot);
}





Show Form
No comments yet. Be the first to add a comment!