CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   Fluent UDF and Scheme Programming (https://www.cfd-online.com/Forums/fluent-udf/)
-   -   Please check out my parallelized udf code (https://www.cfd-online.com/Forums/fluent-udf/89376-please-check-out-my-parallelized-udf-code.html)

aleisia June 10, 2011 16:16

Please check out my parallelized udf code
 
Hi! I want to model a filter (but not modeling it as a porous media), in a room I have SO2-air mixture. First I want to get the SO2 mass flow rate at the inlet surface of the filter, then multiply it by 0.999989, and set the sink rate of the filter volume as -0.999989*(SO2 mass flow rate at the inlet surface)/(Volume of filter). For the outlet of the filter, I set it as "interior", so you can see the filter is not perfect, and my simulation is always transient.

Below is my code, please advise. The red-colored lines are those I'm not so sure about, and I will ask some questions after the code.

Parallel udf
#include "udf.h"

static int inlet_surface_ID = 12;
static int filter_volume_ID = 2;

DEFINE_ADJUST(adjust, d)
{
#if !RP_HOST
int i
real A[ND_ND],
flux[ND_ND];
real NV_VEC(flux), NV_VEC(A); /* declaring vectors flux and A */
real source, massflowrate=0, vol=0;
real ti = RP_Get_Real("flow-time"); /* ti = CURRENT_TIME;*/
face_t f;
cell_t c;
Thread *t, *thread;
t= Lookup_Thread(d, inlet_surface_ID); /* defining the inlet surface thread by specifying the Zone_ID*/
thread= Lookup_Thread(d, filter_volume_ID); /* defining the filter volume thread by specifying the Zone_ID*/
#endif /* !RP_HOST */

/* Send the ID value to all the nodes */
host_to_node_int_2(inlet_surface_ID, filter_volume_ID); /* Does nothing in serial */
host_to_node_real_4(f. t, c, thread); /* Does nothing in serial, t is the thread of inlet surface, thread is the thread of the filter volume */

#if !RP_HOST
/*Start to calculate the mass flow rate through the inlet surface and store it in UDM*/
begin_f_loop(f,t)

if PRINCIPAL_FACE_P(f,t) /* tests if the face is the principle face FOR COMPILED UDFs ONLY */
{
NV_D(flux, =, F_U(f,t), F_V(f,t), F_W(f,t)); /* defining flux in terms of velocity field */
NV_S(flux, *=, F_R(f,t)) /* multiplying density to get flux vector */
F_AREA(A,f,t) /* face normal vector returned from F_AREA */
massflowrate+= F_YI(f,t,i)*NV_DOT(flux,A); /* dot product of the inlet surface flux and area vector, multiplied by the mass fraction of species i */
}
end_f_loop(f,t)


# if RP_NODE /* Perform node synchronized actions here, Does nothing in Serial */
massflowrate = PRF_GRSUM1(massflowrate);
# endif /* RP_NODE */


begin_f_loop(f,t)
if PRINCIPAL_FACE_P(f,t) /* tests if the face is the principle face FOR COMPILED UDFs ONLY */
{
F_UDMI(f, t, 0)= massflowrate;
}
end_f_loop(f,t)


/*Start to calculate the total volume of filter volume and store it in UDM */
begin_c_loop(c,thread)
{
vol += C_VOLUME(c,thread); /* get cell volume */
}
end_c_loop(c,thread)
# if RP_NODE /* Perform node synchronized actions here, Does nothing in Serial */
vol= PRF_GRSUM1(vol);
# endif /* RP_NODE */
begin_c_loop(c,thread)
{
C_UDMI(c, thread, 1)= vol;
}
end_c_loop(c,thread)
#endif /* !RP_HOST */
}

DEFINE_SOURCE(cell_SO2mass_source, c, thread, dS, eqn)
{

#if !RP_HOST
int i
real A[ND_ND], flux[ND_ND];
real NV_VEC(flux), NV_VEC(A); /* declaring vectors flux and A */
real source, massflowrate=0, vol=0;
real ti = RP_Get_Real("flow-time"); /* ti = CURRENT_TIME;*/
face_t f;
Thread *t, *thread;
d = Get_Domain(1);
t= Lookup_Thread(d, inlet_surface_ID); /* defining the inlet surface thread by specifying the Zone_ID*/
thread= Lookup_Thread(d, filter_volume_ID); /* defining the filter volume thread by specifying the Zone_ID*/
#endif /* !RP_HOST */

#if !RP_HOST

Massflowrate= F_UDMI(f, t, 0);
vol = C_UDMI(c, thread, 1);

#endif /* !RP_HOST */

/* Pass the node's SO2 mass flow rate and volume to the Host for calculating source */
node_to_host_real_2(massflowrate, vol); /* Does nothing in SERIAL */

#if !RP_NODE /* SERIAL or HOST */
source=-0.999989* massflowrate/ vol;
dS[eqn]=0.0;

return source;
Message("Sink Rate in Filter %d is %f (kg/m^3/s)\n", filter_volume_ID,( =-0.999989* massflowrate/ vol));
#endif /* !RP_NODE */

}


Questions:

1.I set the inlet surface Zone_ID and filter volume Zone_ID after looking them up in my fluent "BOUNDARY CONDITIONS" panel. It "
static int inlet_surface_ID = 12;" fine, or should I define it this way-> "Define inlet_surface_ID = 12;"?
2. In my DEFINE_SOURCE part, I define the d=Get_Domain(1), d is actually the domain of filter volume, but in DEFINE_ADJUST, I have to call a domain, is it OK that I wrote DEFINE_ADJUST(adjust, d)? Is this "d" in DEFINE_ADJUST the same "d" in my DEFINE_SOURCE? If not, what should I do to make them the same?
3. I've already declared flux and A as vectors, so is the first line here redundant?

real A[ND_ND],
flux[ND_ND];
real NV_VEC(flux), NV_VEC(A); /* declaring vectors flux and A */
Should I keep both lines or delete the first one?
4. Even though my simulation is transient, I don't have if condition involving time, i.e., my so2 release was always on till the time that I stopped my simulation, so I don't need this line
real ti = RP_Get_Real("flow-time"); /* ti = CURRENT_TIME;*/, right?
5. Do I have to pass the data from host to nodes in DEFINE_ADJUST, like what I did above:
/* Send the ID value to all the nodes */

host_to_node_int_2(inlet_surface_ID, filter_volume_ID); /* Does nothing in serial */
host_to_node_real_4(f, t, c, thread); /* Does nothing in serial, t is the thread of inlet surface, thread is the thread of the filter volume */
I guess host_to_node_int_2(inlet_surface_ID, filter_volume_ID); is not necessary, and can be totally deleted, right? Do I need to add node_to_host in DEFINE_ADJUST? I guess not, because in ADJUST, I just need to designate massflowrate and vol some UDM to store them, only in DEFINE_SOURCE do I need to obtain these two values again and return the source I defined, right?
6. Is it fine that designate the UDM above: F_UDMI(f, t, 0) and C_UDMI(c, thread, 1) in DEFINE_ADJUST? f is the inlet surface, t is the inlet surface thread, 0 is the corresponding index; c is the cell in filter volume, thread is the thread for filter volume, and 1 is the corresponding index. I know I should go to "defined->user defined->memory" and select "2" to store these two quantities, so F_UDMI will be called User Memory 0, and C_UDMI will be called User Memory 1, right?
7. There is a line: if PRINCIPAL_FACE_P(f,t) /* tests if the face is the principle face FOR COMPILED UDFs ONLY */ for the principle face, is there any corresponding line for the cells?
8. Is my last few lines in DEFINE_SOURCE right?

#if !RP_NODE /* SERIAL or HOST */
source=-0.999989* massflowrate/ vol;
dS[eqn]=0.0;

return source;
Message("Sink Rate in Filter %d is %f (kg/m^3/s)\n", filter_volume_ID,( =-0.999989* massflowrate/ vol));
#endif

What I meant for is that, after the nodes get back to host, I can write in the host the definition of "source" instead of in the nodes. My way of definition would be equivalent to setting "source term" in FLUENT graphical interface, right?

9. My biggest doubt is that, I know host_to_node is for host to pass data first to node-0, then all the nodes, I know that node_to_host is just for node-0 to pass data to host, so how about all the nodes to node-0?
I got the above code from the idea in official UDF manual example 7.8 parallel udf: Global Summation of Pressure on a Face Zone and its Area Average Computation, in there it seems that the code developer was aware of this "nodes to node-0" communication, but they just used host_to_node first, then node_to_host, how come they can achieve the data communication between nodes and node? I really don't understand! Please advise.

Thanks!




All times are GMT -4. The time now is 08:13.