sandbox/fintzin/Rising-Suspenion/Drop.h

    Declaration of the structures gathering all the properties linked to a droplet.

    • The property of the drop are indexed and just “a” in the code.
    typedef struct {

    physical properties

      double vol;     // volume 
      double S;       // surface   
      double p;       // pressure 
      double W2;     // internal fluctuation
      coord Y;        // position of the center of mass
      coord U;        // averaged velocity
      coord Uc;       // centered velocity
      coord Fh;       // drag force 
      coord D_nbr;    // distance to the nearest neigboring particles 
      coord Per;      // Indicator to identify teh peeriodicity of a drop
      tens P;         // moment of momentum tensor defined as $\int \bm{ru} dV$
      tens G;         // shape tensor defined as $\int \bm{rr} dV$
      double Gnorm;   // norm of the inertia tensor 
      double Pnorm;   // norm of the moment of momentum tensor  
      tens WW;      // tensor product of the inner fluctuation tensor around Uc
    • @brief Think about how to compute the first moments of the surface
    • forces body forces and hydrodynamic forces
    • You might add the int of the stress here
    • so that you can compute the sum of each moments.
    • What about the centered grad of velocity ?
      tens Mh;        // First hydrodinamical moment.  
      tens Sig;       // Sigma stress tesnor 
      tens Ms;        // Moment of the surface tension  
      double ed;      // energy dissipation
    • bilan on NRJ

    Other properties linked to the identification

      double ct;    // contact time with the nearest neigbor 
      int tagmin;   // tag of the nearest droplet
      int tag;
      int tagmax;
      int realtag;
      int si;
      int adj[100]; // maximum index of scalar feilds  
    } Drop;

    assign a value to detect if a drop cross a bounday

    void isperio(scalar s, scalar tag ,int nb,int tagi, Drop n[] ){
      coord per1[nb],per2[nb];
      for (int i = 0; i < nb; i++) 
        foreach_dimension() 
          per1[i].x = 0,per2[i].x = 0;
    
      foreach(reduction(+:per1[:nb]) reduction(+:per2[:nb]))
        if (s[] != nodata && dv() > 0.  && s[]>=EPS) {
          int i=tag[]-1;
          coord pos = POS;
          foreach_dimension(){
            if(pos.x>(L0/2-0.2*D)) 
              per1[i].x = 1;
            else if(pos.x<-(L0/2-0.2*D)) 
              per2[i].x = 1;
          }
        }
    
      for (int i = 0; i < nb; i++) 
        foreach_dimension()
          n[tagi+i].Per.x = (per1[i].x && per2[i].x);
    }

    compute the center of mass and average velocity of the drop

    void pos_vol_and_vel(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      double volume[nb];
      coord posG[nb],v[nb];
      for (int i = 0; i < nb; i++){
        volume[i]=0;
        posG[i]=v[i]=Coord_nul;
      }
      foreach(reduction(+:posG[:nb]) reduction(+:v[:nb]) reduction(+:volume[:nb]))
        if (s[] != nodata && dv() > 0. && s[]>=EPS){
          int i=tag[]-1;
          volume[i] += dv()*s[];
          coord pos = POS;
          pos = POS_perio(pos,n[tagi+i].Per);
          foreach_dimension(){
            posG[i].x    += dv()*s[]*pos.x;
            v[i].x       += dv()*s[]*u.x[];
          }
        }
      for(int i=0;i<nb;i++){
        n[tagi+i].vol = volume[i];
        n[tagi+i].Y = volume[i] ? div_coord(posG[i],volume[i]) : Coord_nul;
        n[tagi+i].U = volume[i] ? div_coord(v[i],volume[i]) : Coord_nul;
      }
    }

    store the value of the velocity feild at the center of mass location for each drops

    void points_vel(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      for(int i=0;i<nb;i++){
        coord velc_loc={0},velc_global = {0};
        #if dimension == 2
        double a = n[i].Y.x ,b=n[i].Y.y;
        foreach_dimension()
          velc_loc.x = interpolate(u.x,a,b) < 100*normL2_coord(n[i].U) ? interpolate(u.x,a,b) : 0. ;
        #elif dimension == 3
        double a = n[i].Y.x ,b=n[i].Y.y, c = n[i].Y.z;
        foreach_dimension()
          velc_loc.x = interpolate(u.x,a,b,c) < 20*normL2_coord(n[i].U) ? interpolate(u.x,a,b,c) : 0. ;
        #endif
        #if _MPI
        MPI_Allreduce(&velc_loc.x, &velc_global.x, dimension, MPI_DOUBLE, MPI_SUM,MPI_COMM_WORLD);
        #else
        velc_global = velc_loc;
        #endif
        n[tagi+i].Uc = velc_global;
      }
    }

    compute the inner velocity w_i dV turbulent tensor \int w_i w_j dv and \int w^c_i dV

    void compute_WW_W2(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      tens WW[nb];
      double W2[nb];
      for (int i = 0; i < nb; i++) {
        WW[i] = tens_nul;
        W2[i] = 0;
      }
      foreach (reduction (+:WW[:nb]) reduction(+:W2[:nb]))
        if (s[] != nodata && dv() > 0.  && s[]>=EPS) {
          int i=tag[]-1;
          einstein_sum(i,j){
            WW[i].i.j += (u.i[] - n[tagi+i].U.i)*(u.j[] - n[tagi+i].U.j)*dv()*s[];
            W2[i] += (u.i[] - n[tagi+i].U.i)*(u.j[] - n[tagi+i].U.j)*dv()*s[];
          }
        }
    
      for(int i=0;i<nb;i++){
        n[tagi+i].WW =  WW[i];
        n[tagi+i].W2 =  W2[i];
      }
    }

    compute the moment of momentum of the drop P = r_i u_j dV

    void compute_G_and_P(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      // need to check the periodicity 
      tens G[nb],P[nb];
      for (int i = 0; i < nb; i++) 
          G[i]=P[i]=tens_nul;
      foreach (reduction (+:G[:nb]) reduction (+:P[:nb]))
        if (s[] != nodata && dv() > 0.  && s[]>=EPS) {
          int i=tag[]-1;
          coord Pos = POS;
          coord r = dist_perio_coord(Pos,n[tagi+i].Y);
          einstein_sum(i,j){
            G[i].i.j += r.i * r.j   * dv() * s[];
            P[i].i.j += r.i * u.j[] * dv() * s[];
          }
        }
      for(int i=0;i<nb;i++){
        n[tagi+i].G = G[i];
        n[tagi+i].P = P[i];
        n[tagi+i].Gnorm = tens_norm(G[i]);
        n[tagi+i].Pnorm = tens_norm(P[i]);
      }
    }

    Compute the integral of the newtonian stress tensor

    void compute_Mh(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      tens Mh[nb],Sig[nb];
      double ed[nb],pressure[nb];
      for (int i = 0; i < nb; i++){
        ed[i] = 0;
        pressure[i] = 0;
        Mh[i]     = tens_nul;
        Sig[i]     = tens_nul;
      }
      foreach (reduction (+:Sig[:nb])  reduction (+:Mh[:nb]) 
              reduction (+:ed[:nb]) reduction(+:pressure[:nb]))
        if (s[] != nodata && dv() > 0.  && s[]>=EPS) {
          int i = tag[]-1;
          pressure[i] += p[]*s[]*dv();
          tens gradU,S,rdivS,rdivp;
          coord gradp,LapU;
          coord Pos = POS;
          coord r = dist_perio_coord(Pos,n[tagi+i].Y);
          vec_grad(u,gradU);
          vec_lap(u,LapU);
          scalar_grad(p,gradp);
          // need to think about what tensor is needed
          einstein_sum(i,j){
            S.i.j = (gradU.i.j+gradU.j.i)*mu1; 
            rdivp.i.j = r.i * gradp.j;
            rdivS.i.j = r.i * LapU.j * mu1;
            Sig[i].i.j += S.i.j * s[] * dv();
            Mh[i].i.j += (S.i.j - rdivp.i.j + rdivS.i.j)*s[]*dv();
            ed[i] += S.i.j*gradU.i.j*s[]*dv();
          }
        }
      for(int i=0; i<nb; i++){
        n[tagi+i].Mh      = Mh[i];
        n[tagi+i].Sig     = Sig[i];
        n[tagi+i].ed      = ed[i];
        n[tagi+i].p       = pressure[i];
      }
    }

    compute the integral of the surface tension force and its moment

    void compute_S_and_Ms(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      double S[nb];
      tens Ms[nb];    
      for (int i = 0; i < nb; i++){
        Ms[i] = tens_nul;
        S[i] = 0;
      }
      foreach(reduction(+:S[:nb]) reduction(+:Ms[:nb])){
        int i = tag[]-1; 
        if(s[] != nodata && dv() > 0. && s[] > EPS && s[] < 1. - EPS){
          int i = tag[]-1;
          coord  normal = mycs(point, s), p;
          double alpha = plane_alpha(s[], normal);
          double dS = pow(Delta, dimension - 1) * plane_area_center(normal, alpha, &p);
          S[i] += dS;
        }
    
        if(i < 0){
          foreach_neighbor(1)
            i = max(i,tag[]-1);
        }
        if(i>=0){
          coord Pos = POS;
          coord r = dist_perio_coord(Pos,n[tagi+i].Y);
          coord acc = {a.x[1],
                       a.y[0,1],
                       a.z[0,0,1]};
    
          coord grad = {s[1] != s[-1],
                        s[0,1] != s[0,-1],
                        s[0,0,1] != s[0,0,-1]};
          einstein_sum(i,j){
            Ms[i].i.j += (grad.j && fm.j[] > 0) ?
                        r.i * (acc.j+a.j[])/2. * (f[]*(rho1-rho2)+rho2) * dv() :0.;
          }
        }
      }
    
      for(int i=0; i<nb; i++){
        n[tagi+i].S    = S[i];
        n[tagi+i].Ms   = Ms[i];
      }
    }
    
    
    void Compute_drops (scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      isperio(s,tag,nb,tagi,n); 
      pos_vol_and_vel(s,tag,nb,tagi,n);
    
      for(int i=0;i<nb;i++)
        foreach_dimension()
          if (n[tagi+i].Y.x>L0/2.) 
            n[tagi+i].Y.x -= L0; // set the pos inside the domain 
    
      points_vel(s,tag,nb,tagi,n);

    second order term calculation appearing in the * moment of momentum equation

      compute_G_and_P(s,tag,nb,tagi,n);
      compute_WW_W2(s,tag,nb,tagi,n);
      compute_Mh(s,tag,nb,tagi,n);
      compute_S_and_Ms(s,tag,nb,tagi,n);
    }

    funciton that link every drops from one step to the next by the variable tag

    void assign_tags_from_last_step (Drop datat0[],Drop datat1[],int tagi){
      int tags_avail[tagi];
      for(int k = 0;k<tagi;k++){
        datat1[k].tag = -1;
        tags_avail[k]=0;
      }
      for (int j = 0; j < datat0[0].tagmax; j++)
      {
        coord np = add_coord(datat0[j].Y,mult_coord(datat0[j].U,dtprint)); // euleur schem
        #if dimension == 2
        double r = sqrt(datat0[j].vol/M_PI)*0.5; // 
        #else
        double r = pow(datat0[j].vol/M_PI,1./3.)*3./4.; // 
        #endif
        bool probleme_of_assignement = true;
        for (int k = j; k < (tagi+j); k++)
        {
          int idx = k % tagi;
          coord np1 = datat1[idx].Y;
          double dist = dist_perio(np,np1);
          if(dist<r*0.5){
            datat1[idx].tag = datat0[j].tag;
            probleme_of_assignement = false;
            break;
          }
        }
        if(probleme_of_assignement){
          fprintf(stdout,"Pbug : X  %g, Y  %g, Z  %g\n",np.x,np.y,np.z);
          fprintf(stdout,"Error of assignement at t = %g for bubble tag = %d tm %d j %d vol %g \n",
                  t,datat0[j].tag,datat0[0].tagmax,j,datat0[j].vol);
        }
      }

    to reassgin tags when coalescence and breakup event occure

      int ta = 0;
      for (int k = 0; k < tagi; k++){
        bool avail = true;
        for (int j = 0; j < tagi; j++)
          if (k == datat1[j].tag)
            avail = false;
        if(avail) {
          tags_avail[ta] = k;
          ta++;
        }
        if(datat1[k].tag>=tagi) datat1[k].tag=-1;
      }
    
      int new_tag=0;
      for (int k = 0; k < tagi; k++){
        if(datat1[k].tag == -1 && new_tag<=ta){
          if(tags_avail[new_tag] >= tagi) new_tag++;
          datat1[k].tag = tags_avail[new_tag];
          new_tag++;
        }
      }
    }

    print the distance between each droplets and store the tag of the closest * dorplet of a given droplet. besides it store the contact time

    void print_pair_dist(Drop data0[],Drop data[],int tagi,int step, float t){
      Drop data_orderred[tagi];
      for (int j = 0; j < tagi; j++)
      {
        data[j].ct = 0;
        foreach_dimension()
          data[j].D_nbr.x = Ls*100;
        data_orderred[data[j].tag]=data[j];
      }
      foreach_dimension(){
        Dist_x = fopen(name_x,"a");
        fprintf(Dist_x,"%d,%g",step,t);
      }
      for (int k = 0; k < tagi; k++)
      {
        coord npi = data_orderred[k].Y; 
        for (int j = k+1; j<tagi;j++){
          coord npj = data_orderred[j].Y;
          coord distcoord = dist_perio_coord(npj,npi);
          double dist = normL2_coord(distcoord);
    
          foreach_dimension() 
            fprintf(Dist_x,",%g",distcoord.x);
    
          if(dist < normL2_coord(data_orderred[k].D_nbr)){
            data_orderred[k].D_nbr    = distcoord;
            data_orderred[k].tagmin   = j;
          } 
          if(dist < normL2_coord(data_orderred[j].D_nbr)){
            data_orderred[j].D_nbr    = mult_coord(distcoord,-1);
            data_orderred[j].tagmin   = k;
          }
        }
        for (int j = 0; j < tagi; j++)
        {
          if(data[j].tag == k) {
            data[j].D_nbr = data_orderred[k].D_nbr;
            data[j].tagmin = data_orderred[k].tagmin;
          }
        }
      }
      
      foreach_dimension(){
        fprintf(Dist_x,"\n");
        fclose(Dist_x);
      }
      #if COAL
      Drop data_orderred0[data0[0].tagmax];
    
      // compute the contact time
      for (int j = 0; j < data0[0].tagmax; j++)
        data_orderred0[data0[j].tag]=data0[j];
      for(int k = 0; k<tagi;k++){
        int tag = data[k].tag;
        int tm = data[k].tagmin;
        double Dia  = sqrt(data_orderred[tm].vol/ M_PI )+sqrt(data[k].vol/ M_PI );
        if((normL2_coord(data[k].D_nbr) <= Dia) && (data[k].adj[data_orderred[tm].si] == true)){
          if(tag >= data0[0].tagmax) data[k].ct = dtprint;
          if(tag <  data0[0].tagmax) data[k].ct = data_orderred0[tag].ct + dtprint;
        }
      }
      #endif
    }

    Function that print the property of the droplets in fDrop.csv and * print the pair dist in Dist_x.csv

    void print_Drop(Drop data0[],Drop data1[],int tagi,int step,double time){
      fDrop = fopen("fDrop.csv","a");
      for(int j=0;j<tagi;j++){
        fprintf(fDrop,"%d,%g,%d",step,time,data1[0].tagmax);
        fprintf(fDrop,",%g",data1[j].vol);
        fprintf(fDrop,",%g",data1[j].S);
        fprintf(fDrop,",%g",data1[j].ed);
        fprintf(fDrop,",%g",data1[j].Gnorm);
        fprintf(fDrop,",%g",data1[j].Pnorm);
        fprintf(fDrop,",%g",data1[j].p);
        fprintf(fDrop,",%g",data1[j].W2);
        einstein_sum(i,j){
          fprintf(fDrop,",%g",data1[j].Y.i);
          fprintf(fDrop,",%g",data1[j].U.i);
          fprintf(fDrop,",%g",data1[j].Uc.i);
          fprintf(fDrop,",%g",data1[j].D_nbr.i);
          fprintf(fDrop,",%g",data1[j].Fh.i);
          fprintf(fDrop,",%g",data1[j].G.i.j);
          fprintf(fDrop,",%g",data1[j].P.i.j);
          fprintf(fDrop,",%g",data1[j].WW.i.j);
          fprintf(fDrop,",%g",data1[j].Sig.i.j);
          fprintf(fDrop,",%g",data1[j].Mh.i.j);
          fprintf(fDrop,",%g",data1[j].Ms.i.j);
        }
        fprintf(fDrop,",%g",data1[j].ct);
        fprintf(fDrop,",%d",data1[j].tagmin);
        fprintf(fDrop,",%d",data1[j].tag);
        fprintf(fDrop,"\n");
      }
      fclose(fDrop);
    }
    
    
    #if COAL
    
    void neighboring_scalar(scalar s, scalar tag ,int nb,int tagi,Drop n[]){
      int taggg[nb];
      int nvar = datasize/sizeof(double), len = nb*nvar, adj[len],tc[len];
      for (int i = 0; i < len; i++) adj[i] = false;
      for (int i = 0; i < nb; i++) taggg[i]=tc[i]=0;
      foreach(reduction(max:taggg[:nb])  reduction(max:tc[:nb]) 
              reduction(max:adj[:nvar]))
        if (s[] != nodata && dv() > 0.  && s[]>=EPS) {
          int i=tag[]-1;
          taggg[i] = tag[];
          foreach_neighbor()
          for(scalar c in interfaces)
            if(c.i != s.i && c[] > EPS)
              adj[i*c.i + c.i] = true;
      }
      for (int i = 0; i < nb; i++){
        n[tagi+i].realtag = taggg[i];
        for(scalar c in interfaces){
         n[tagi+i].adj[c.i] = adj[i*c.i + c.i];
        }
      } 
    }

    coalescence function. * It is activated only if COAL = 1

    void coalescence(Drop data[],int tagi){
      Drop DAT[tagi];
      for (int j = 0; j < tagi; j++) DAT[data[j].tag]=data[j];
      scalar b[];
    
      for(scalar c in interfaces){
        foreach(){
          b[] = c[]>EPS;}
        tag (b);
    
        int si[tagi],realtag[tagi]; 
        for (int i = 0; i < tagi; i++) si[i]=realtag[i]=-1;
        for(int j = 0 ;j < tagi ; j++){
          if(DAT[j].ct != 0.){
            fprintf(stdout,"time %g the tag %d %d ct %g\n",t,j,DAT[j].tag,DAT[j].ct);
            Drop b1 = DAT[j];
            Drop b2 = DAT[DAT[j].tagmin];
            double d_eq = 2*sqrt(b2.vol/M_PI)*sqrt(b1.vol/M_PI) / (sqrt(b2.vol/M_PI) + sqrt(b1.vol/M_PI));
            double V_0 = normL2_coord(diff_coord(b1.U,b2.U)); 
            double td = rho_f*sq(d_eq)*V_0/(8*sig);
            double We = rho_f*d_eq*sq(V_0)/(2*sig);
            fprintf(stdout,"coalescence time td = %g We = %g deq %g vel %g\n",td,We,d_eq,V_0);
            if (DAT[j].ct > td && DAT[j].si  != DAT[DAT[j].tagmin].si && c.i == DAT[j].si) {
              // for(int l = 0 ;l < tagi ; l++){
                // int tm = DAT[j].tag;
                // if(DAT[l].tag != DAT[j].tag && DAT[l].tag != DAT[tm].tag){
                //   if(DAT[l].adj[DAT[j].si] == 1 && DAT[l].si == DAT[tm].si)
                //   if(DAT[l].tagmin == DAT[j].tag){
                //   fprintf(stdout,"l too close too [");
                //   for(scalar s in interfaces) fprintf(stdout,"(%d,%d),",DAT[l].adj[s.i],s.i);
                //   fprintf(stdout,"]\n");
                //   }
                // }else{
                  realtag[j] = DAT[j].realtag;
                  si[j] = DAT[DAT[j].tagmin].si;
                  DAT[j].si  = DAT[DAT[j].tagmin].si;
                  fprintf(stdout,"add to caaol realt %d si objc %d\n",si[j],realtag[j]);
              //   }
              // }
            }
          }
        }
        #if _MPI
            MPI_Bcast(si,tagi,MPI_INT,0,MPI_COMM_WORLD);
            MPI_Bcast(realtag,tagi,MPI_INT,0,MPI_COMM_WORLD);
        #endif
        for (int i = 0; i < tagi; i++)
          if(si[i] != -1)
          foreach()
            if(b[] == realtag[i]){
            scalar t = {si[i]};
            t[] = c[]; 
            c[] = 0.;
            }
        scalar * list = list_copy ({c});
        for (int i = 0; i < tagi; i++)
          if(si[i] != -1)
            list = list_add(list,(scalar){si[i]});
        boundary (list);
        free (list);
      }
    }
    #endif