sandbox/boniouv/collision_statistics/collision.h
Collision statistics from eulerian fields
#define nscmax 10
#ifndef EPS
#define EPS 1e-6
#endif
FILE * fDrop;
FILE * fPair;
double totVol = 0.;
scalar nsc_coloring[]; // Color by number of simultaneous contact
Declaration of the structure gathering properties of a pair of droplets.
typedef struct {
int tag; // pair tag
double age; // age of interaction
coord R; // pair relative distance
coord W; // pair relative velocity
double Sc; // contact surface
int cc; // boolean for contact Sc>0
int cm; // boolean for contact d<D+Dx
int cp; // boolean for contact d<1.01D
double tcc; // contact time for contact Sc>0
double tcm; // contact time for contact Sc>0
double tcp; // contact time for contact Sc>0
} pair;
Declaration of the structure gathering all the properties linked to a droplet.
typedef struct {
physical properties
int tag; // tag of the droplet
double V; // volume
double S; // surface
double ke; // kinetic energy
double se; // surface energy
double vd; // viscous dissipation
double Tv; // viscous power
double Tp; // pressure power
double Phis; // power of surface tension
double Phit; // power of surface tension
double de; // dissipated energy
double Sph; // Sphericity
double AR; // Aspect ratio
coord Y; // position of the center of mass
coord U; // averaged velocity
coord Fh; // force on droplet
coord Fsig; // force on droplet
coord Ftp; // force on droplet
coord Ftv; // force on droplet
coord Fth; // force on droplet
mat3 UpUp; // Reynolds stress tensor
Properties related to nearest pair
Properties related to pairs in interaction
int nsci; // number of interactions
int nscc; // number of contacts
int nscm; // number of contacts
int nscp; // number of contacts
int ncc; // number of collisions
int ncm; // number of collisions
int ncp; // number of collisions
pair pint[nscmax]; // Interaction list
Other properties linked to the identification
int j0; // index of the droplet in the list at previous time
int tagmax; // number of droplets in the Drop list
int si; // index of the scalar field f associated
coord Per; // indicator to identify the periodicity of a drop
} Drop;
Compute all the properties of each droplet in the Drop list
Compute the crucial properties of the droplet: X,U,V,S
void initialize_droplets(scalar interfaces[], scalar s,
scalar tag, int nd, int tagi, Drop n[])
{
double Vtot[nd], Stot[nd];
coord posG[nd], Ud[nd];
for (int i = 0; i < nd; i++){
Vtot[i] = Stot[i] = 0.;
posG[i] = Ud[i] = coord_null;
}
foreach(reduction(+:posG[:nd])
reduction(+:Ud[:nd])
reduction(+:Vtot[:nd])
reduction(+:Stot[:nd]))
if (s[] != nodata && dv() > 0. && s[]>=EPS){
int i=tag[]-1;
double vol = dv()*s[];
Vtot[i] += vol;
if (s[] < 1. - EPS) {
coord normal = mycs(point, s), parea;
double alpha = plane_alpha(s[], normal);
// Compute surface of fragment with centroid parea
double dS = pow(Delta, dimension - 1) * plane_area_center(normal, alpha, &parea);
Stot[i] += dS;
}
coord pos = POS;
pos = POS_perio(pos,n[tagi+i].Per);
foreach_dimension(){
posG[i].x += vol*pos.x;
Ud[i].x += vol*u.x[];
}
}
// Gather all properties for each droplet
for(int i = 0; i < nd; i++){
n[tagi+i].S = Stot[i];
n[tagi+i].V = Vtot[i];
n[tagi+i].Y = Vtot[i] ? div_coord(posG[i],Vtot[i]) : coord_null;
n[tagi+i].U = Vtot[i] ? div_coord(Ud[i],Vtot[i]) : coord_null;
// set the pos inside the domain
foreach_dimension()
if (n[tagi+i].Y.x>L0/2.)
n[tagi+i].Y.x -= L0;
}
}
Compute the properties related to interactions between droplets
void droplet_neighbours(Drop n[], int nd)
{
Drop nsort[nd]; // Sorted version of n
int invj[nd]; // invj(tag) = index
for (int j = 0; j < nd; j++)
{
foreach_dimension()
n[j].pnrst.R.x = Ls*100;
n[j].nsci = 0;
n[j].nscc = 0;
n[j].nscm = 0;
n[j].nscp = 0;
nsort[n[j].tag] = n[j];
invj[n[j].tag] = j;
}
// Check for all possible pairs
for (int k = 0; k < nd; k++)
{
coord npi = nsort[k].Y;
for (int j = k+1; j < nd; j++){
coord npj = nsort[j].Y;
coord distcoord = dist_perio_coord(npi,npj);
double dist = normL2_coord(distcoord);
if(dist < normL2_coord(nsort[k].pnrst.R)){
nsort[k].pnrst.R = distcoord;
nsort[k].pnrst.W = diff_coord(nsort[k].U,nsort[j].U);
nsort[k].pnrst.tag = j;
}
if(dist < normL2_coord(nsort[j].pnrst.R)){
nsort[j].pnrst.R = mult_coord(distcoord,-1);
nsort[j].pnrst.W = diff_coord(nsort[j].U,nsort[k].U);
nsort[j].pnrst.tag = k;
}
// Look for droplets in contact
nsort[k].nsci += (dist < 1.5*D1);
nsort[j].nsci += (dist < 1.5*D1);
if (dist < 1.5*D1){
int nsck = min(nsort[k].nsci - 1,nscmax-1);
int nscj = min(nsort[j].nsci - 1,nscmax-1);
nsort[k].pint[nsck].tag = j;
nsort[j].pint[nscj].tag = k;
nsort[k].pint[nsck].R = distcoord;
nsort[j].pint[nscj].R = mult_coord(distcoord,-1);
nsort[k].pint[nsck].W = diff_coord(nsort[k].U,nsort[j].U);
nsort[j].pint[nscj].W = diff_coord(nsort[j].U,nsort[k].U);
}
}
}
for (int k = 0; k < nd; k++)
{
int j = invj[k];
n[j].pnrst = nsort[k].pnrst;
n[j].nsci = nsort[k].nsci;
for (int nscj = 0; nscj < min(n[j].nsci,nscmax); nscj++)
n[j].pint[nscj] = nsort[k].pint[nscj];
}
}
double sphericity(mat3 Ms)
{
// #if dimension == 2
// double vMs[2] = {0.};
// double data[4] = {Ms.x.x,Ms.x.y,
// Ms.y.x,Ms.y.y};
// // eigen(data, vMs, 2);
// // return sqrt(vMs[0]/vMs[1]);
// #else
// double vMs[3] = {0.};
// double data[9] = {Ms.x.x,Ms.x.y,Ms.x.z,
// Ms.y.x,Ms.y.y,Ms.y.z,
// Ms.z.x,Ms.z.y,Ms.z.z};
// eigen(data, vMs, 3);
// return sqrt(vMs[0]/vMs[2]);
// #endif
return 0.*Ms.x.x; // fixme: call to gsl_eigen.h from gsl
}
double aspect_ratio(double V, double S)
{
#if dimension == 2
return sqrt(4.*M_PI*V)/S;
#else
return pow(36.*M_PI*sq(V),1./3.)/S;
#endif
}
compute the droplet properties which requires an integral over * discrete cells. The cells belonging to droplet i are identified * using the tag_list. By looping over all interfaces/tags, the integral * can be computed. The routine is used to compute the surface of contact * between droplets, the sphericity, aspect ratio and Reynolds stress tensor.
void droplet_integrals(scalar interfaces[], scalar tag_list[], Drop n[], int nd)
{
double Sci[nd*nscmax];
for (int i = 0; i < nscmax*nd; i++) {
Sci[i] = 0.;
}
foreach(reduction(+:Sci[:nscmax*nd])) {
scalar s,ts;
for (s,ts in interfaces,tag_list)
if (s[] != nodata && dv() > 0. && s[]>=EPS){
int i = ts[] - 1;
coord pos = POS;
if (s[] < 1. - EPS){
coord normal = mycs(point, s), parea;
double alpha = plane_alpha(s[], normal);
// Compute surface of fragment with centroid parea
double dS = pow(Delta, dimension - 1) * plane_area_center(normal, alpha, &parea);
coord Yints = add_coord(pos,mult_coord(parea,Delta));
// Check for neighboring cells with different drop tag
scalar c,tc;
for(c,tc in interfaces,tag_list) {
int j = tc[] - 1; // Only used if in contact
bool is_nghb = false;
foreach_neighbor(1)
if (c[] != nodata && dv() > 0. && c.i != s.i && c[] > EPS && c[] < 1. - EPS){
coord normalc = mycs(point, c), pareac;
double alphac = plane_alpha(c[], normalc);
plane_area_center(normalc, alphac, &pareac);
coord posn = POS;
coord Yintc = add_coord(posn,mult_coord(pareac,Delta));
coord distcoord = dist_perio_coord(Yints,Yintc);
is_nghb = normL2_coord(distcoord) < Delta || is_nghb;
if (is_nghb) j = tc[] - 1;
}
if (is_nghb) {
// Find if the cell in contact has its tag k in the contact list of droplet j
for (int nsci = 0; nsci < min(n[i].nsci,nscmax); nsci++) {
if (n[i].pint[nsci].tag == n[j].tag) {
Sci[i*nscmax + nsci] += dS;
break;
}
}
}
}
}
}
}
// Compute vectors needed for reduction
vector SU[],pU[];
foreach()
{
mat3 gradU,S;
vec_grad(u,gradU);
einstein_sum(i,j){
S.i.j = gradU.i.j + gradU.j.i;
SU.i[] = 0.;
}
einstein_sum(i,j){
SU.i[] += S.i.j*u.j[];
pU.i[] = p[]*u.i[];
}
};
double ke[nd], vd[nd], Tv[nd], Tp[nd], Phis[nd], Phit[nd];
coord Fsig[nd], Ftp[nd], Ftv[nd];
mat3 Ms[nd], UpUp[nd];
for (int i = 0; i < nd; i++) {
ke[i] = vd[i] = Tv[i] = Tp[i] = Phis[i] = Phit[i] = 0.;
Fsig[i] = Ftp[i] = Ftv[i] = coord_null;
Ms[i] = UpUp[i] = tens_null;
}
scalar * Fsig_list = list_clone(interfaces); // Store tags in a list
scalar s,Fsigs;
for (s,Fsigs in interfaces,Fsig_list) {
curvature(s, Fsigs, SIG);
}
foreach(reduction(+:ke[:nd])
reduction(+:vd[:nd])
reduction(+:Tv[:nd])
reduction(+:Tp[:nd])
reduction(+:Phis[:nd])
reduction(+:Phit[:nd])
reduction(+:Fsig[:nd])
reduction(+:Ftp[:nd])
reduction(+:Ftv[:nd])
reduction(+:UpUp[:nd])
reduction(+:Ms[:nd])) {
scalar s,ts,Fsigs;
for (s,ts,Fsigs in interfaces,tag_list,Fsig_list)
if (s[] != nodata && dv() > 0. && s[]>=EPS){
int i = ts[] - 1;
double vol = dv()*s[];
coord pos = POS;
if (s[] < 1. - EPS){
coord normal = mycs(point, s), pvol, parea;
double alpha = plane_alpha(s[], normal);
// Compute volume of fragment with centroid pvol
plane_center (normal, alpha, s[], &pvol);
// The centroid of the interface volume is corrected (not equal to cell centroid)
pos = add_coord(pos,mult_coord(pvol,Delta));
double dS = pow(Delta, dimension - 1) * plane_area_center(normal, alpha, &parea);
foreach_dimension() {
Fsig[i].x += dS*Fsigs[]*normal.x;
Phis[i] += Fsig[i].x*u.x[];
}
}
coord r = dist_perio_coord(pos,n[i].Y);
double dist = sq(normL2_coord(r));
mat3 gradU; vec_grad(u,gradU);
double divSU,divPU;
vec_div(SU,divSU);
vec_div(pU,divPU);
Tv[i] += vol*divSU;
Tp[i] += vol*divPU;
coord lapU; vec_lap(u,lapU);
foreach_dimension(){
ke[i] += vol*sq(u.x[]);
#if TFALL
Phit[i] += vol*rho_d*An*sq(u.x[]);
#endif
Ftp[i].x -= vol*(pf[1] - pf[])/Delta;
Ftv[i].x += vol*lapU.x;
}
einstein_sum(i,j){
vd[i] += vol*gradU.i.j*gradU.i.j;
Ms[i].i.j += vol*(dist*I.i.j - r.i*r.j);
UpUp[i].i.j += vol*(u.i[] - n[i].U.i)*(u.j[] - n[i].U.j);
}
}
}
delete (Fsig_list), free (Fsig_list);
for (int i = 0; i < nd; i++) {
for (int nsci = 0; nsci < min(n[i].nsci,nscmax); nsci++) {
n[i].pint[nsci].Sc = Sci[i*nscmax + nsci];
}
n[i].AR = aspect_ratio(n[i].V,n[i].S);
n[i].Sph = sphericity(Ms[i]);
n[i].ke = n[i].V ? 0.5*rho_d*ke[i]/n[i].V : 0.0;
n[i].se = n[i].S*SIG;
n[i].vd = n[i].V ? mu_d*vd[i]/n[i].V : 0.0;
n[i].Tv = n[i].V ? mu_d*Tv[i]/n[i].V : 0.0;
n[i].Tp = n[i].V ? Tp[i]/n[i].V : 0.0;
n[i].Phis = Phis[i];
n[i].Phit = Phit[i];
n[i].Fsig = Fsig[i];
n[i].Ftp = n[i].V ? div_coord(Ftp[i],n[i].V) : coord_null;
n[i].Ftv = n[i].V ? mult_coord(Ftv[i],mu_d/n[i].V) : coord_null;
n[i].Fth = add_coord(n[i].Ftp,n[i].Ftv);
n[i].UpUp = n[i].V ? div_tens(UpUp[i],n[i].V) : tens_null;
}
}
Compute the temporal values such as forces, contact time and number of collision
void droplet_temporal(Drop n0[], Drop n[], int nd)
{
for (int j = 0; j < nd; j++){
int k = n[j].j0;
// Check if the droplet already existed in last timestep
if (k >= 0) {
// Increment the energy dissipated
n[j].de = n0[k].de + dtprint*n[j].vd;
// Compute the linear momentum
coord qi = mult_coord(n[j].U, n[j].V*rho_d);
coord q0 = mult_coord(n0[k].U, n0[k].V*rho_d);
coord dqdt = div_coord(diff_coord(qi,q0),dtprint);
n[j].Fh = dqdt;
// The correlation R*F can also be computed for the PFP term
einstein_sum(i,j){
n[j].RFh.i.j += (n[j].pnrst.R.i * dqdt.j);
}
// Increment collision time for the contact lists
for (int nscj = 0; nscj < min(n[j].nsci,nscmax); nscj++)
{
n[j].pint[nscj].age = 0.0;
n[j].pint[nscj].tcc = 0.0;
n[j].pint[nscj].tcm = 0.0;
n[j].pint[nscj].tcp = 0.0;
double dist = normL2_coord(n[j].pint[nscj].R);
n[j].pint[nscj].cc = (n[j].pint[nscj].Sc > 0.0005*SURF);
n[j].pint[nscj].cm = (dist < D1 + Dx);
n[j].pint[nscj].cp = (dist < 1.05*D1);
n[j].nscc += n[j].pint[nscj].cc;
n[j].nscm += n[j].pint[nscj].cm;
n[j].nscp += n[j].pint[nscj].cp;
for (int nsck = 0; nsck < min(n0[k].nsci,nscmax); nsck++)
{
if (n[j].pint[nscj].tag == n0[k].pint[nsck].tag)
{
n[j].pint[nscj].age = n0[k].pint[nsck].age + dtprint;
n[j].pint[nscj].tcc = (n[j].pint[nscj].cc && n0[k].pint[nsck].cc) ? n0[k].pint[nsck].tcc + dtprint : 0.;
n[j].pint[nscj].tcm = (n[j].pint[nscj].cm && n0[k].pint[nsck].cm) ? n0[k].pint[nsck].tcm + dtprint : 0.;
n[j].pint[nscj].tcp = (n[j].pint[nscj].cp && n0[k].pint[nsck].cp) ? n0[k].pint[nsck].tcp + dtprint : 0.;
break;
}
}
}
// Increment age, collision number and collision time
n[j].pnrst.age = (n[j].pnrst.tag == n0[k].pnrst.tag) ? n0[k].pnrst.age + dtprint : 0.;
n[j].ncc = n0[k].ncc + max(n[j].nscc - n0[k].nscc,0);
n[j].ncm = n0[k].ncm + max(n[j].nscm - n0[k].nscm,0);
n[j].ncp = n0[k].ncp + max(n[j].nscp - n0[k].nscp,0);
}
}
}
void assign_tags_from_last_step (Drop n0[], Drop n[], int nd){
int tags_avail[nd];
for(int j = 0; j<nd; j++) {
n[j].tag = -1;
tags_avail[j] = 0;
}
for (int j = 0; j < nd; j++)
{
bool problem_of_assignement = nd > 0;
#if dimension == 2
double r = sqrt(n[j].V/M_PI)*0.5;
#else
double r = pow(n[j].V/M_PI,1./3.)*3./4.;
#endif
n[j].tag = j;
coord np = n[j].Y;
for (int k = 0; k < nd; k++)
{
coord U12 = mult_coord(add_coord(n0[k].U,n[j].U),0.5);
coord np0 = add_coord(n0[k].Y,mult_coord(U12,dtprint)); // Euler step with lag velocity
double dist = dist_perio(np0,np);
if(dist<r*0.5){
n[j].tag = n0[k].tag;
n[j].j0 = k;
problem_of_assignement = false;
break;
}
}
if(problem_of_assignement){
if (pid() == 0) {
fprintf(stderr,"Error of assignement at t = %g for droplet %d with V %g \n",
t,j,n[j].V);
}
n[j].tag = -1; // -1 so it is fixed by reassignment
n[j].j0 = -1; // -1 means that this droplet did not exist in the last step
}
}
to reassgin tags when coalescence and breakup event occure
int ta = 0;
for (int k = 0; k < nd; k++){
bool avail = true;
for (int j = 0; j < nd; j++)
if (k == n[j].tag)
avail = false;
if (avail) {
tags_avail[ta] = k;
ta++;
}
if (n[k].tag >= nd) n[k].tag=-1;
}
int new_tag=0;
for (int k = 0; k < nd; k++){
if (n[k].tag == -1 && new_tag<=ta) {
if(tags_avail[new_tag] >= nd) new_tag++;
n[k].tag = tags_avail[new_tag];
new_tag++;
if (pid() == 0) {
fprintf(stderr,"New tag assignement at t = %g for droplet j %d new tag %d \n",
t,k,n[k].tag);
}
}
}
}
assign a value to detect if a droplet cross a boundary
void isperio(scalar s, scalar tag, int nd, int tagi, Drop n[])
{
coord per1[nd],per2[nd];
for (int i = 0; i < nd; i++)
foreach_dimension()
per1[i].x = 0,per2[i].x = 0;
foreach(reduction(+:per1[:nd]) reduction(+:per2[:nd]))
if (s[] != nodata && dv() > 0. && s[]>=EPS){
int i=tag[]-1;
coord pos = POS;
foreach_dimension(){
if(pos.x>(L0/2-0.2*D1))
per1[i].x = 1;
else if(pos.x<-(L0/2-0.2*D1))
per2[i].x = 1;
}
}
for (int i = 0; i < nd; i++){
foreach_dimension()
n[tagi+i].Per.x = (per1[i].x && per2[i].x);
}
}
Update the nsc_coloring field with the new droplet list
void fill_nsc_coloring(scalar interfaces[], scalar tag_list[], Drop n[])
{
foreach() {
scalar s,ts;
for (s,ts in interfaces,tag_list)
if (s[] != nodata && dv() > 0. && s[] >= EPS) {
int i = ts[] - 1;
nsc_coloring[] = max(nsc_coloring[],n[i].nscc);
}
}
scalar nsc_coloringTmp[];
foreach(){
double max_color = 0.;
foreach_neighbor(1){
max_color = max(max_color,nsc_coloring[]);
}
nsc_coloringTmp[] = max_color;
}
foreach() nsc_coloring[] = nsc_coloringTmp[];
}
update all drops quantities
int update_droplets(scalar interfaces[], Drop drops[])
{
int tagi = 0;
int ndrop;
A temporary droplet list is created to store the previous timestep. * This allows to keep track of the droplet changes in time and assign * the correct tag to the new droplets
Drop dropsTmp[Nb+Nbsup];
memcpy(dropsTmp, drops, sizeof(Drop)*(Nb+Nbsup));
foreach() nsc_coloring[] = 0.;
scalar * tag_list = list_clone(interfaces); // Store tags in a list
Loop over all interface fields created to prevent coalescence. * The tag_list will store the produced tag fields related to each interface.
scalar s,ts;
for(s,ts in interfaces,tag_list) {
scalar tag_level[];
foreach() tag_level[] = s[]> EPS;
ndrop = tag(tag_level);
isperio(s,tag_level,ndrop,tagi,drops);
initialize_droplets(interfaces,s,tag_level,ndrop,tagi,drops); // compute each drop properties
for(int j = 0; j < ndrop; j++) {
if (drops[tagi+j].V < 0.1*VOL) { //Fragment suppression
fprintf(stderr,"t %g remove frag tag %d with volume: %g \n",t,drops[tagi+j].tag,drops[tagi+j].V);
double vol = 0.;
foreach(reduction(+:vol))
if (tag_level[] == j + 1) {
vol += s[]*dv();
s[]=0;
tag_level[] = 0;
}
else if (tag_level[] > j + 1) tag_level[] -= 1; // shift the tag_level field
totVol += vol;
fprintf(stderr,"\n");
// remove the fragment from the list by replacing the others
for(int k = j; k < ndrop-1; k++)
drops[tagi+k] = drops[tagi+k + 1];
ndrop -= 1;
j -= 1;
}
}
// Store the tag in the tag_list (with the tagi shift)
foreach() {
ts[] = tag_level[];
if (tag_level[] > 0)
ts[] += tagi;
}
for(int k = 0; k < ndrop; k++) {
drops[tagi].si = s.i;
tagi++;
}
}
Assign tags from last step and fix the tag issues * with coalescence/breakup events
drops[0].tagmax = tagi;
assign_tags_from_last_step (dropsTmp,drops,tagi);
Compute droplet interaction with neighbours, * temporal quantities and droplet integrals
droplet_neighbours(drops,tagi);
droplet_integrals(interfaces,tag_list,drops,tagi);
droplet_temporal(dropsTmp,drops,tagi);
Fill nsc_coloring used on VOF fragment in video
fill_nsc_coloring(interfaces,tag_list,drops);
delete (tag_list), free (tag_list);
fprintf(stderr,"Total volume loss by removing fragments: %g\n",totVol);
return tagi;
}
- This funciton initialize a random array of non touching spheres
- so that the simulation reach a random state faster.
int check_all_dist(const coord * Position,const double * Radii, int j){
double dr = sqrt(dimension)*Ls/(1 << 7);
for (int k = 0; k < j; k++){
if(dist_perio(Position[j],Position[k]) < ((Radii[j]+Radii[k]) + dr))
return 0;
}
return 1;
}
void generate_drops_pos(coord * Positions, double * Radii, double ndrops)
{
#if _MPI
MPI_Barrier(MPI_COMM_WORLD);
#endif
srand(time(NULL));
int j = 0;
int ntry = 0;
if (pid() == 0) fprintf (stderr, "Generating random droplet positions...\n");
while (j < ndrops) {
ntry++;
assert (ntry < 10000000000*ndrops);
double Rm = (double) RAND_MAX + 1.0;
Positions[j].x = ((double) rand()/Rm) * Ls - Ls/2;
Positions[j].y = ((double) rand()/Rm) * Ls - Ls/2;
Positions[j].z = ((double) rand()/Rm) * Ls - Ls/2;
if(check_all_dist(Positions, Radii,j)) {
if (pid() == 0) fprintf (stderr, "Found a position for droplet %d in %d tries!\n",j,ntry);
j++;
ntry = 0;
}
}
if (pid() == 0) fprintf (stderr, "Found all droplet positions!\n");
}
void read_drops_pos(coord * Positions, char * file, int ndrops)
{
FILE * fp = fopen(file, "r");
assert (fp);
srand(time(NULL));
int j = 0;
if (pid() == 0) fprintf (stderr, "Reading droplet position in file...\n");
while (j < ndrops) {
assert(fscanf(fp, "%lf,%lf,%lf",
&Positions[j].x,
&Positions[j].y,
&Positions[j].z) == 3);
if (pid() == 0) fprintf(stderr,"Found a position for droplet %d: %g,%g,%g\n",j,
Positions[j].x,Positions[j].y,Positions[j].z);
j++;
}
if (pid() == 0) fprintf (stderr, "Found all droplet positions!\n");
fclose(fp);
}
Function that print the property of the droplets in fDrop.csv and * print the pair dist in Dist_x.csv
void print_droplets(Drop drops[], int nd, double time)
{
fDrop = fopen("drops_ic.csv","a");
for(int j = 0; j < nd; j++){
fprintf(fDrop,"%g",time);
fprintf(fDrop,",%d",drops[j].tag);
einstein_sum(i,j){
fprintf(fDrop,",%g",drops[j].Y.i);
fprintf(fDrop,",%g",drops[j].U.i);
}
fprintf(fDrop,",%g",drops[j].V);
fprintf(fDrop,",%g",drops[j].S);
fprintf(fDrop,",%g",drops[j].Sph);
fprintf(fDrop,",%g",drops[j].AR);
fprintf(fDrop,",%g",drops[j].ke);
fprintf(fDrop,",%g",drops[j].vd);
fprintf(fDrop,",%g",drops[j].se);
fprintf(fDrop,",%g",drops[j].Tv);
fprintf(fDrop,",%g",drops[j].Tp);
fprintf(fDrop,",%g",drops[j].Phis);
fprintf(fDrop,",%g",drops[j].Phit);
fprintf(fDrop,",%g",drops[j].de);
fprintf(fDrop,",%d",drops[j].pnrst.tag);
einstein_sum(i,j){
fprintf(fDrop,",%g",drops[j].pnrst.R.i);
fprintf(fDrop,",%g",drops[j].pnrst.W.i);
}
fprintf(fDrop,",%g",drops[j].pnrst.age);
fprintf(fDrop,",%d",drops[j].ncc);
fprintf(fDrop,",%d",drops[j].ncm);
fprintf(fDrop,",%d",drops[j].ncp);
fprintf(fDrop,",%d",drops[j].nsci);
fprintf(fDrop,",%d",drops[j].nscc);
fprintf(fDrop,",%d",drops[j].nscm);
fprintf(fDrop,",%d",drops[j].nscp);
einstein_sum(i,j){
fprintf(fDrop,",%g",drops[j].Fh.i);
fprintf(fDrop,",%g",drops[j].Fsig.i);
fprintf(fDrop,",%g",drops[j].Ftp.i);
fprintf(fDrop,",%g",drops[j].Ftv.i);
fprintf(fDrop,",%g",drops[j].Fth.i);
fprintf(fDrop,",%g",drops[j].UpUp.i.j);
}
fprintf(fDrop,"\n");
}
fclose(fDrop);
fPair = fopen("drops_pair.csv","a");
for(int j = 0; j < nd; j++){
for (int nscj = 0; nscj < min(drops[j].nsci,nscmax); nscj++)
{
fprintf(fPair,"%g",time);
fprintf(fPair,",%d",drops[j].tag);
fprintf(fPair,",%d",drops[j].pint[nscj].tag);
einstein_sum(i,j){
fprintf(fPair,",%g",drops[j].pint[nscj].R.i);
fprintf(fPair,",%g",drops[j].pint[nscj].W.i);
}
fprintf(fPair,",%g",drops[j].pint[nscj].age);
fprintf(fPair,",%g",drops[j].pint[nscj].tcc);
fprintf(fPair,",%g",drops[j].pint[nscj].tcm);
fprintf(fPair,",%g",drops[j].pint[nscj].tcp);
fprintf(fPair,",%g",drops[j].pint[nscj].Sc);
fprintf(fPair,"\n");
}
}
fclose(fPair);
}
void dump_drops(Drop drops[], int nd, double time, char * file)
{
FILE * fp = fopen(file, "w");
fprintf(fp,"Time: %g,",time);
fprintf(fp,"Ndrops: %d\n",nd);
for(int j = 0; j < nd; j++){
fprintf(fp,"Drop %d:\n",drops[j].tag);
einstein_sum(i,j){
fprintf(fp,"%g,",drops[j].Y.i);
fprintf(fp,"%g,",drops[j].U.i);
}
fprintf(fp,"%g\n",drops[j].de);
fprintf(fp,"%d",drops[j].pnrst.tag);
fprintf(fp,",%g\n",drops[j].pnrst.age);
fprintf(fp,"%d,",drops[j].ncc);
fprintf(fp,"%d,",drops[j].ncm);
fprintf(fp,"%d\n",drops[j].ncp);
fprintf(fp,"%d,",drops[j].nsci);
fprintf(fp,"%d,",drops[j].nscc);
fprintf(fp,"%d,",drops[j].nscm);
fprintf(fp,"%d\n",drops[j].nscp);
for (int nscj = 0; nscj < nscmax; nscj++)
{
fprintf(fp,"%d,",drops[j].pint[nscj].tag);
fprintf(fp,"%g,",drops[j].pint[nscj].age);
fprintf(fp,"%g,",drops[j].pint[nscj].tcc);
fprintf(fp,"%g,",drops[j].pint[nscj].tcm);
fprintf(fp,"%g\n,",drops[j].pint[nscj].tcp);
}
}
fclose(fp);
}
Function that print the property of the droplets in fDrop.csv and * print the pair dist in Dist_x.csv
int restore_drops(Drop drops[], char * file)
{
if (pid() == 0) fprintf (stderr, "Restoring droplets from previous simulation...\n");
FILE * fp = fopen(file, "r");
double loctime;
int nd;
fscanf(fp,"Time: %lf,",&loctime);
fscanf(fp,"Ndrops: %d\n",&nd);
for(int j = 0; j < nd; j++){
fscanf(fp,"Drop %d:\n",&drops[j].tag);
einstein_sum(i,j){
fscanf(fp,"%lf,",&drops[j].Y.i);
fscanf(fp,"%lf,",&drops[j].U.i);
}
fscanf(fp,"%lf\n",&drops[j].de);
fscanf(fp,"%d",&drops[j].pnrst.tag);
fscanf(fp,",%lf\n",&drops[j].pnrst.age);
fscanf(fp,"%d,",&drops[j].ncc);
fscanf(fp,"%d,",&drops[j].ncm);
fscanf(fp,"%d\n",&drops[j].ncp);
fscanf(fp,"%d,",&drops[j].nsci);
fscanf(fp,"%d,",&drops[j].nscc);
fscanf(fp,"%d,",&drops[j].nscm);
fscanf(fp,"%d\n",&drops[j].nscp);
for (int nscj = 0; nscj < nscmax; nscj++)
{
fscanf(fp,"%d,",&drops[j].pint[nscj].tag);
fscanf(fp,"%lf,",&drops[j].pint[nscj].age);
fscanf(fp,"%lf,",&drops[j].pint[nscj].tcc);
fscanf(fp,"%lf,",&drops[j].pint[nscj].tcm);
fscanf(fp,"%lf\n,",&drops[j].pint[nscj].tcp);
}
}
int ivtk = (int)(t/2/teddy-25.);
if (pid() == 0) fprintf (stderr, "Restored all droplets! Next sol: %d\n",ivtk);
fclose(fp);
return ivtk;
}
event init(t = 0)
{
if (pid() == 0) {
fDrop = fopen("drops_ic.csv","w");
#if dimension == 2
fprintf (fDrop, "t,tag,x,y,ux,uy,V,S,Sph,AR,ke,vd,se,Tv,Tp,Phis,Phit,de,tagn,rx,ry,wx,wy,age,");
fprintf (fDrop, "ncc,ncm,ncp,nsci,nscc,nscm,nscp,");
fprintf (fDrop, "Fhx,Fhy,Fsigx,Fsigy,Ftpx,Ftpy,Ftvx,Ftvy,Fthx,Fthy,");
fprintf (fDrop, "UUxx,UUxy,UUyx,UUyy\n");
#elif dimension == 3
fprintf (fDrop, "t,tag,x,y,z,ux,uy,uz,V,S,Sph,AR,ke,vd,se,Tv,Tp,Phis,Phit,de,tagn,rx,ry,rz,wx,wy,wz,age,");
fprintf (fDrop, "ncc,ncm,ncp,nsci,nscc,nscm,nscp,");
fprintf (fDrop, "Fhx,Fhy,Fhz,Fsigx,Fsigy,Fsigz,Ftpx,Ftpy,Ftpz,Ftvx,Ftvy,Ftvz,Fthx,Fthy,Fthz,");
fprintf (fDrop, "UUxx,UUxy,UUxz,UUyx,UUyy,UUyz,UUzx,UUzy,UUzz\n");
#endif
fclose(fDrop);
fPair = fopen("drops_pair.csv","w");
#if dimension == 2
fprintf (fPair, "t,tag,tagc,rx,ry,wx,wy,age,tcc,tcm,tcp,Sc\n");
#elif dimension == 3
fprintf (fPair, "t,tag,tagc,rx,ry,rz,wx,wy,wz,age,tcc,tcm,tcp,Sc\n");
#endif
fclose(fPair);
#if RESTORE
copy_file("../restart/drops_ic.csv","drops_ic.csv",fDrop);
copy_file("../restart/drops_pair.csv","drops_pair.csv",fPair);
#endif
}
}
References
[cannon2023morphology] |
Ianto Cannon, Giovanni Soligo, and Marco E Rosti. Morphology of clean and surfactant-laden droplets in homogeneous isotropic turbulence. arXiv preprint arXiv:2307.15448, 2023. |