UDF for profile transfer (velocity, temperature, species.......etc) across a non-conformal interface which seprates volumes of different mesh size



This is a problem which we often come across. Many times it happens that in some volumes we need finer mesh resolution while on others we need very coarse mesh. This leads to non-conformal mesh across the volumes.Fluent does the zeroth order interpolation while transferring the data (velocity, temperature, species mass fraction...etc) from one mesh to other. This leads to mass imbalance if the mesh size vary greatly across the boundary.This UDF corrects for the mass loss that occurs across the interface.
The approach of this UDF is something like this. Firstly the profiles from the exit of vol1 (velocity, temp, species ...etc) are written out from one of the volumes whose exit is inlet to some other volume. Then these profile are read in to the other volume as inlet boundary conditions.Fluent does the zeroth order interpolation for all (i.e velocity, temperature, species etc) ( since there is number of nodes mismatch across two volumes) while assigining the values at the inlet.These values at the inlet are read through the UDF (which is plugged in through 'Execute on Demand') at all the inlet bounday nodes and the total mass flux coming in from the inlet (of vol2) is calculated. Again mass flux coming out from the exit of vol1 is calculated by reading the values from profile file. Next a multiplication factor(old mass flow rate/new mass flow rate) is calculated and is multiplied to all velocity components. Similar procedure is implemented for species conservation across the boundary.This ensures that mass and species are conserved while transferring the data although it might not conserve the velocity profiles since a constant multiplication factor is used at all the nodes which is an average value. This approach is not any higher order interpolation but simply total mass is conserved.Below I am writing the steps of using the UDF

1. case has to be 3d
2. write out profiles of density, u, v, w, temp, all species, and x-surface-area, y-surface-area and z-surface-area into input.prof
3. you can use this input.prof to set up profiles of u, v, w temp, species for the new case at inlet.
4. after 1 iteration, execute_on_demand this udf. You can see the display of old and new mass flow rate, species mass fraction in cortex window.
5. An output file named output.prof will be written. Read this file it will overwrite the inlet boundary conditions with corrected velocities and species mass fraction.
6. Again give one iteration and execute_on_demand the UDF to see if the mass flow rate and species mass fraction are corrected or not.The old and new values should closely match.
6. you will need to set the no of species in n_spe variable in the udf.
7. you will need to set the inlet face zone id in inlet_id variable.

Below is attached the UDF :

######################################################################################

#include "udf.h"
#include "dpm.h"
#include "surf.h"
#define n_spe 6
#define inlet_id 7
DEFINE_ON_DEMAND(matchprof)
{
Domain *d = Get_Domain(1);
CX_Cell_Id cx_cell;
cell_t c, cc;
face_t f, ff;
Thread *t, *tt;
FILE* input;
FILE* input2;
FILE* output;
int i, j,npoints;
char junk[80],h1[80],h2[80],h3[80],sp_name[n_spe][80],c_n[ND_ND][10],bl2_nm[ND_ND+2][80];
char f_an[ND_ND][30];
real A[ND_ND], f_den, f_u, f_v, f_w, mass_tot, mass_f, mass_tot_old,mass_frac_sp;
real x[10000], y[10000], z[10000],mult_fact_vel,mult_fact_spe[n_spe];
real x_ar[10000], y_ar[10000], z_ar[10000], den[10000], u[10000];
real v[10000], w[10000], temp[10000], y_spe[n_spe][10000], num_read, mass_of_specie[n_spe];
real mass_spe[n_spe][10000], total_mass_spe[n_spe];

Thread *ift = Lookup_Thread(d, inlet_id);

mass_tot = 0.0;

for (i=0; i< n_spe; i++)
{
mass_of_specie[i]=0.0 ;
}

begin_f_loop(f, ift)
{
F_AREA(A,f,ift);
f_den = F_R(f,ift);
f_u = F_U(f,ift);
f_v = F_V(f,ift);
f_w = F_W(f,ift);
mass_f = ABS(f_den * (f_u * A[0]+ f_v*A[1] + f_w*A[2]));
mass_tot = mass_tot + mass_f;

for (i=0; i< n_spe; i++)
{
mass_frac_sp= F_YI(f,ift,i);
mass_of_specie[i]=mass_of_specie[i] + mass_f*mass_frac_sp ;
}
}
end_f_loop(f, in_facet)

for (i=0; i< n_spe; i++)
{
CX_Message("n New mass flow rate of specie ( %d) = %g n",i, mass_of_specie[i]);
}

if (!(input = fopen("input.prof","r")))
{
Message0("nnWarning: Could not find input file for data points...n");
return;
}

if (!(output = fopen("output.prof","w")))
{
Message0("nnWarning: Could not open output file (check permissions on directory)...n");
fclose(input);
return;
}

/* Read first line of the profile file to get the number of points*/
fscanf(input, "%s %s %d %s n", &h1, &h2, &npoints, &h3);

/* read the x, y, z coordinates*/
i=0;
for (i=0; i<ND_ND; i++)
{
fscanf(input, "%s n", &c_n[i]);
j = 0;
for (j=0; j<npoints; j++)
{
fscanf(input, "%f n", &num_read);
switch (i)
{
case 0:
x[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 1:
y[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 2:
z[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
}
}
fscanf(input, "%s n", &junk);
}

/* get density, u, v, w and temperature from the profile file*/
i=0;
for (i=0; i<(ND_ND+2); i++)
{
j = 0;
fscanf(input, "%s n", &bl2_nm[i]);
/* CX_Message("%s n", &bl2_nm[i]);*/
for (j=0; j<npoints; j++)
{
fscanf(input, "%f n",&num_read);
switch (i)
{
case 0:
den[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 1:
u[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 2:
v[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 3:
w[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 4:
temp[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
}
}
fscanf(input, "%s n", &junk);
}

/* get all species points from the file*/
i=0;
for (i = 0; i < n_spe; i++)
{
total_mass_spe[i] = 0.0;
j = 0;
fscanf(input, "%s n", &sp_name[i]);
for (j=0; j<npoints; j++)
{
fscanf(input, "%f n",&num_read);
y_spe[i][j] = num_read;
/* fprintf(output, "%d t %d t %f n",i, j, num_read);*/
}
fscanf(input, "%s n", &junk);
}

/*get x, y, and Z surface area from the profile file*/
i =0;
for (i = 0; i < ND_ND; i++)
{
/* CX_Message("read s area %d %s n", 0, &bl2_nm[0]);*/
j = 0;
fscanf(input, "%s n", &f_an[i]);
for (j=0; j<npoints; j++)
{
fscanf(input, "%f n",&num_read);

switch (i)
{
case 0:
x_ar[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 1:
y_ar[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
case 2:
z_ar[j] = num_read;
/* fprintf(output, "%d %f n",i, num_read);*/
break;
default:
CX_Message("None of the above");
break;
}
}

fscanf(input, "%s n", &junk);
}
mass_tot_old =0.0;
i =0;
for(i=0; i<npoints; i++)
{
mass_f = ABS(den[i] * (u[i] * x_ar[i] + v[i]*y_ar[i] + w[i]*z_ar[i]));
mass_tot_old = mass_tot_old +mass_f;
j =0;
for (j =0; j < n_spe; j++)
{
mass_spe[j][i] = y_spe[j][i]*mass_f;
total_mass_spe[j] = total_mass_spe[j]+ mass_spe[j][i];
}
}
CX_Message("n Old Mass Flow Rate was %f n",mass_tot_old);
CX_Message("n New Mass Flow Rate was %f n",mass_tot);

for (i=0; i< n_spe; i++)
{
CX_Message("n Old mass flow rate of specie ( %d) = %g n",i, total_mass_spe[i]);
}

mult_fact_vel = mass_tot_old/mass_tot;

for(i=0; i < n_spe; i++)
{
mult_fact_spe[i]=total_mass_spe[i]/mass_of_specie[i];
}

/*Write out a new profile file */
fprintf(output, "%s %s %d%s n", h1, h2, npoints, h3);

/* write the x, y, z coordinates*/
i=0;
for (i=0; i<3; i++)
{
fprintf(output, "%s n", &c_n[i]);

j = 0;
for (j=0; j<npoints; j++)
{

switch (i)
{
case 0:
fprintf(output, "%f n", x[j]);
break;
case 1:
fprintf(output, "%f n", y[j]);
break;
case 2:
fprintf(output, "%f n", z[j]);
break;
}
}
fprintf(output, ") n");
}

/* write density, temperature and scaled values of u, v, w*/

i=0;
for (i=0; i<(ND_ND+2); i++)
{
j = 0;
/* CX_Message("%d %s n", i, &bl2_nm[i]);*/

fprintf(output, "%s n", &bl2_nm[i]);
for (j=0; j<npoints; j++)
{
switch (i)
{
case 0:
fprintf(output, "%f n",den[j]);
break;
case 1:
fprintf(output, "%f n",mult_fact_vel*u[j]);
break;
case 2:
fprintf(output, "%f n",mult_fact_vel*v[j]);
break;
case 3:
fprintf(output, "%f n",mult_fact_vel*w[j]);
break;
case 4:
fprintf(output, "%f n",temp[j]);
break;
}
}
fprintf(output, ") n");
}

/* write all species points from the file*/
i=0;
for (i = 0; i < n_spe; i++)
{
j = 0;
fprintf(output, "%s n", &sp_name[i]);
for (j=0; j<npoints; j++)
{
fprintf(output, "%f n",(mult_fact_spe[i]/mult_fact_vel)*y_spe[i][j]);
}
fprintf(output, ") n");
}

/*write x, y, and Z surface area to the new profile file*/
i =0;
for (i = 0; i < ND_ND; i++)
{
j = 0;
fprintf(output, "%s n", &f_an[i]);
for (j=0; j<npoints; j++)
{

switch (i)
{
case 0:
fprintf(output, "%f n",x_ar[j]);
break;
case 1:
fprintf(output, "%f n",y_ar[j]);
break;
case 2:
fprintf(output, "%f n",z_ar[j]);
break;
default:
CX_Message("None of the above");
break;
}
}
fprintf(output, ") n");
}
fprintf(output, ") n");

fclose(input);

fclose(output);

}


###################################################################################################





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