コード例 #1
0
void FluidSim::compute_phi() {
   
   //Estimate from particles
   liquid_phi.assign(3*dx);
   for(unsigned int p = 0; p < particles.size(); ++p) {
      Vec2f point = particles[p];
      int i,j;
      float fx,fy;
      //determine containing cell;
      get_barycentric((point[0])/dx-0.5f, i, fx, 0, ni);
      get_barycentric((point[1])/dx-0.5f, j, fy, 0, nj);
      
      //compute distance to surrounding few points, keep if it's the minimum
      for(int j_off = j-2; j_off<=j+2; ++j_off) for(int i_off = i-2; i_off<=i+2; ++i_off) {
         if(i_off < 0 || i_off >= ni || j_off < 0 || j_off >= nj)
            continue;
         
         Vec2f pos((i_off+0.5f)*dx, (j_off+0.5f)*dx);
         float phi_temp = dist(pos, point) - 1.02f*particle_radius;
         liquid_phi(i_off,j_off) = min(liquid_phi(i_off,j_off), phi_temp);
      }
   }
   
   //"extrapolate" phi into solids if nearby
   for(int j = 0; j < nj; ++j) {
      for(int i = 0; i < ni; ++i) {
         if(liquid_phi(i,j) < 0.5*dx) {
            float solid_phi_val = 0.25f*(nodal_solid_phi(i,j) + nodal_solid_phi(i+1,j) + nodal_solid_phi(i,j+1) + nodal_solid_phi(i+1,j+1));
            if(solid_phi_val < 0)
               liquid_phi(i,j) = -0.5f*dx;
         }
      }
   }  
}
コード例 #2
0
//Compute finite-volume style face-weights for fluid from nodal signed distances
void FluidSim::compute_weights() {

   for(int j = 0; j < u_weights.nj; ++j) for(int i = 0; i < u_weights.ni; ++i) {
      u_weights(i,j) = 1 - fraction_inside(nodal_solid_phi(i,j+1), nodal_solid_phi(i,j));
   }
   for(int j = 0; j < v_weights.nj; ++j) for(int i = 0; i < v_weights.ni; ++i) {
      v_weights(i,j) = 1 - fraction_inside(nodal_solid_phi(i+1,j), nodal_solid_phi(i,j));
   }

}
コード例 #3
0
//Initialize the grid-based signed distance field that dictates the position of the solid boundary
void FluidSim::set_boundary(float (*phi)(const Vec2f&)) {
   
   for(int j = 0; j < nj+1; ++j) for(int i = 0; i < ni+1; ++i) {
      Vec2f pos(i*dx,j*dx);
      nodal_solid_phi(i,j) = phi(pos);
   }

}
コード例 #4
0
//Initialize the grid-based signed distance field that dictates the position of the solid boundary
void FluidSim::set_boundary(float (*phi)(const Vec3f&)) {

   for(int k = 0; k < nk+1; ++k) for(int j = 0; j < nj+1; ++j) for(int i = 0; i < ni+1; ++i) {
      Vec3f pos(i*dx,j*dx,k*dx);
      nodal_solid_phi(i,j,k) = phi(pos);
   }
   
   for(int k = 0; k < nk; ++k) for(int j = 0; j < nj; ++j) for(int i = 0; i < ni; ++i) {
      Vec3f pos((i+0.5f)*dx,(j+0.5f)*dx,(k+0.5f)*dx);
      cell_solid_phi(i,j,k) = phi(pos);
   }

}
コード例 #5
0
void FluidSim::compute_phi() {
   
   //grab from particles
   liquid_phi.assign(3*dx);
   for(unsigned int p = 0; p < particles.size(); ++p) {
      Vec3i cell_ind(particles[p] / dx);
      for(int k = max(0,cell_ind[2] - 1); k <= min(cell_ind[2]+1,nk-1); ++k) {
         for(int j = max(0,cell_ind[1] - 1); j <= min(cell_ind[1]+1,nj-1); ++j) {
            for(int i = max(0,cell_ind[0] - 1); i <= min(cell_ind[0]+1,ni-1); ++i) {
               Vec3f sample_pos((i+0.5f)*dx, (j+0.5f)*dx,(k+0.5f)*dx);
               float test_val = dist(sample_pos, particles[p]) - particle_radius;
               if(test_val < liquid_phi(i,j,k))
                  liquid_phi(i,j,k) = test_val;
            }
         }
      }
   }
   
   //extend phi slightly into solids (this is a simple, naive approach, but works reasonably well)
   Array3f phi_temp = liquid_phi;
   for(int k = 0; k < nk; ++k) {
      for(int j = 0; j < nj; ++j) {
         for(int i = 0; i < ni; ++i) {
            if(liquid_phi(i,j,k) < 0.5*dx) {
               float solid_phi_val = 0.125f*(nodal_solid_phi(i,j,k) + nodal_solid_phi(i+1,j,k) + nodal_solid_phi(i,j+1,k) + nodal_solid_phi(i+1,j+1,k)
                  + nodal_solid_phi(i,j,k+1) + nodal_solid_phi(i+1,j,k+1) + nodal_solid_phi(i,j+1,k+1) + nodal_solid_phi(i+1,j+1,k+1));
               if(solid_phi_val < 0)
                  phi_temp(i,j,k) = -0.5f*dx;
            }
         }
      }
   }
   liquid_phi = phi_temp;
   

}
コード例 #6
0
//Compute finite-volume style face-weights for fluid from nodal signed distances
void FluidSim::compute_weights() {

   //Compute face area fractions (using marching squares cases).
   for(int k = 0; k < nk; ++k) for(int j = 0; j < nj; ++j) for(int i = 0; i < ni+1; ++i) {
      u_weights(i,j,k) = 1 - fraction_inside(nodal_solid_phi(i,j,  k),
                                             nodal_solid_phi(i,j+1,k),
                                             nodal_solid_phi(i,j,  k+1),
                                             nodal_solid_phi(i,j+1,k+1));
      u_weights(i,j,k) = clamp(u_weights(i,j,k),0.0f,1.0f);
   }
   for(int k = 0; k < nk; ++k) for(int j = 0; j < nj+1; ++j) for(int i = 0; i < ni; ++i) {
      v_weights(i,j,k) = 1 - fraction_inside(nodal_solid_phi(i,  j,k),
                                             nodal_solid_phi(i,  j,k+1),
                                             nodal_solid_phi(i+1,j,k),
                                             nodal_solid_phi(i+1,j,k+1));
      v_weights(i,j,k) = clamp(v_weights(i,j,k),0.0f,1.0f);
   }
   for(int k = 0; k < nk+1; ++k) for(int j = 0; j < nj; ++j) for(int i = 0; i < ni; ++i) {
      w_weights(i,j,k) = 1 - fraction_inside(nodal_solid_phi(i,  j,  k),
                                             nodal_solid_phi(i,  j+1,k),
                                             nodal_solid_phi(i+1,j,  k),
                                             nodal_solid_phi(i+1,j+1,k));
      w_weights(i,j,k) = clamp(w_weights(i,j,k),0.0f,1.0f);
   }


}
コード例 #7
0
void FluidSim::solve_viscosity(float dt) {
   int ni = liquid_phi.ni;
   int nj = liquid_phi.nj;
   
   //static obstacles for simplicity - for moving objects, 
   //use a spatially varying 2d array, and modify the linear system appropriately
   float u_obj = 0;
   float v_obj = 0;

   Array2c u_state(ni+1,nj,(const char&)0);
   Array2c v_state(ni,nj+1,(const char&)0);
   const int SOLID = 1;
   const int FLUID = 0;

   printf("Determining states\n");
   //just determine if the face position is inside the wall! That's it.
   for(int j = 0; j < nj; ++j) {
      for(int i = 0; i < ni+1; ++i) {
         if(i - 1 < 0 || i >= ni || (nodal_solid_phi(i,j+1) + nodal_solid_phi(i,j))/2 <= 0)
            u_state(i,j) = SOLID;
         else
            u_state(i,j) = FLUID;
      }
   }


   for(int j = 0; j < nj+1; ++j)  {
      for(int i = 0; i < ni; ++i) {
         if(j - 1 < 0 || j >= nj || (nodal_solid_phi(i+1,j) + nodal_solid_phi(i,j))/2 <= 0)
            v_state(i,j) = SOLID;
         else 
            v_state(i,j) = FLUID;
      }
   }
   
   printf("Building matrix\n");
   int elts = (ni+1)*nj + ni*(nj+1);
   if(vrhs.size() != elts) {
      vrhs.resize(elts);
      velocities.resize(elts);
      vmatrix.resize(elts);
   }
   vmatrix.zero();
   
   float factor = dt/sqr(dx);
   for(int j = 1; j < nj-1; ++j) for(int i = 1; i < ni-1; ++i) {
      if(u_state(i,j) == FLUID ) {
         int index = u_ind(i,j);      
         
         vrhs[index] = u_vol(i,j) * u(i,j);
         vmatrix.set_element(index,index,u_vol(i,j));
         
         //uxx terms
         float visc_right = viscosity(i,j);
         float visc_left = viscosity(i-1,j);
         float vol_right = c_vol(i,j);
         float vol_left = c_vol(i-1,j);

        //u_x_right
         vmatrix.add_to_element(index,index, 2*factor*visc_right*vol_right);
         if(u_state(i+1,j) == FLUID)
            vmatrix.add_to_element(index,u_ind(i+1,j), -2*factor*visc_right*vol_right);
         else if(u_state(i+1,j) == SOLID)
            vrhs[index] -= -2*factor*visc_right*vol_right*u_obj;

         //u_x_left
         vmatrix.add_to_element(index,index, 2*factor*visc_left*vol_left);
         if(u_state(i-1,j) == FLUID)
            vmatrix.add_to_element(index,u_ind(i-1,j), -2*factor*visc_left*vol_left);
         else if(u_state(i-1,j) == SOLID)
            vrhs[index] -= -2*factor*visc_left*vol_left*u_obj;
         
         //uyy terms
         float visc_top = 0.25f*(viscosity(i-1,j+1) + viscosity(i-1,j) + viscosity(i,j+1) + viscosity(i,j));
         float visc_bottom = 0.25f*(viscosity(i-1,j) + viscosity(i-1,j-1) + viscosity(i,j) + viscosity(i,j-1));
         float vol_top = n_vol(i,j+1);
         float vol_bottom = n_vol(i,j);

         //u_y_top
         vmatrix.add_to_element(index,index, +factor*visc_top*vol_top);
         if(u_state(i,j+1) == FLUID)
            vmatrix.add_to_element(index,u_ind(i,j+1), -factor*visc_top*vol_top);
         else if(u_state(i,j+1) == SOLID)
            vrhs[index] -= -u_obj*factor*visc_top*vol_top;
      
         //u_y_bottom
         vmatrix.add_to_element(index,index, +factor*visc_bottom*vol_bottom);
         if(u_state(i,j-1) == FLUID)
            vmatrix.add_to_element(index,u_ind(i,j-1), -factor*visc_bottom*vol_bottom);
         else if(u_state(i,j-1) == SOLID)
            vrhs[index] -= -u_obj*factor*visc_bottom*vol_bottom;
      
         //vxy terms
         //v_x_top
         if(v_state(i,j+1) == FLUID)
            vmatrix.add_to_element(index,v_ind(i,j+1), -factor*visc_top*vol_top);
         else if(v_state(i,j+1) == SOLID)
            vrhs[index] -= -v_obj*factor*visc_top*vol_top;
         
         if(v_state(i-1,j+1) == FLUID)
            vmatrix.add_to_element(index,v_ind(i-1,j+1), factor*visc_top*vol_top);
         else if(v_state(i-1,j+1) == SOLID)
            vrhs[index] -= v_obj*factor*visc_top*vol_top;
     
         //v_x_bottom
         if(v_state(i,j) == FLUID)
            vmatrix.add_to_element(index,v_ind(i,j), +factor*visc_bottom*vol_bottom);
         else if(v_state(i,j) == SOLID)
            vrhs[index] -= v_obj*factor*visc_bottom*vol_bottom;
         
         if(v_state(i-1,j) == FLUID)
            vmatrix.add_to_element(index,v_ind(i-1,j), -factor*visc_bottom*vol_bottom);
         else if(v_state(i-1,j) == SOLID)
            vrhs[index] -= -v_obj*factor*visc_bottom*vol_bottom;
      

      }
   }
   
   for(int j = 1; j < nj; ++j) for(int i = 1; i < ni-1; ++i) {
      if(v_state(i,j) == FLUID) {
         int index = v_ind(i,j);      
         
         vrhs[index] = v_vol(i,j)*v(i,j);
         vmatrix.set_element(index, index, v_vol(i,j));

         //vyy
         float visc_top = viscosity(i,j);
         float visc_bottom = viscosity(i,j-1);
         float vol_top = c_vol(i,j);
         float vol_bottom = c_vol(i,j-1);

         //vy_top
         vmatrix.add_to_element(index,index, +2*factor*visc_top*vol_top);
         if(v_state(i,j+1) == FLUID)
            vmatrix.add_to_element(index,v_ind(i,j+1), -2*factor*visc_top*vol_top);
         else if (v_state(i,j+1) == SOLID)
            vrhs[index] -= -2*factor*visc_top*vol_top*v_obj;
         
         //vy_bottom
         vmatrix.add_to_element(index,index, +2*factor*visc_bottom*vol_bottom);
         if(v_state(i,j-1) == FLUID)
            vmatrix.add_to_element(index,v_ind(i,j-1), -2*factor*visc_bottom*vol_bottom);
         else if(v_state(i,j-1) == SOLID)
            vrhs[index] -= -2*factor*visc_bottom*vol_bottom*v_obj;
         
         //vxx terms
         float visc_right = 0.25f*(viscosity(i,j-1) + viscosity(i+1,j-1) + viscosity(i,j) + viscosity(i+1,j));
         float visc_left = 0.25f*(viscosity(i,j-1) + viscosity(i-1,j-1) + viscosity(i,j) + viscosity(i-1,j));
         float vol_right = n_vol(i+1,j);
         float vol_left = n_vol(i,j);

         //v_x_right
         vmatrix.add_to_element(index,index, +factor*visc_right*vol_right);
         if(v_state(i+1,j) == FLUID)
            vmatrix.add_to_element(index,v_ind(i+1,j), -factor*visc_right*vol_right);
         else if(v_state(i+1,j) == SOLID)
            vrhs[index] -= -v_obj*factor*visc_right*vol_right;
      
         //v_x_left
         vmatrix.add_to_element(index,index, +factor*visc_left*vol_left);
         if(v_state(i-1,j) == FLUID)
            vmatrix.add_to_element(index,v_ind(i-1,j), -factor*visc_left*vol_left);
         else if(v_state(i-1,j) == SOLID)
            vrhs[index] -= -v_obj*factor*visc_left*vol_left;

         //uyx

         //u_y_right
         if(u_state(i+1,j) == FLUID)
            vmatrix.add_to_element(index,u_ind(i+1,j), -factor*visc_right*vol_right);
         else if(u_state(i+1,j) == SOLID)
            vrhs[index] -= -u_obj*factor*visc_right*vol_right;
         
         if(u_state(i+1,j-1) == FLUID)
            vmatrix.add_to_element(index,u_ind(i+1,j-1), factor*visc_right*vol_right);
         else if(u_state(i+1,j-1) == SOLID)
            vrhs[index] -= u_obj*factor*visc_right*vol_right;
      
         //u_y_left
         if(u_state(i,j) == FLUID)
            vmatrix.add_to_element(index,u_ind(i,j), factor*visc_left*vol_left);
         else if(u_state(i,j) == SOLID)
            vrhs[index] -= u_obj*factor*visc_left*vol_left;
          
         if(u_state(i,j-1) == FLUID)
            vmatrix.add_to_element(index,u_ind(i,j-1), -factor*visc_left*vol_left);
         else if(u_state(i,j-1) == SOLID)
            vrhs[index] -= -u_obj*factor*visc_left*vol_left;
      
      }
   }

   
   double res_out;
   int iter_out;
   
   solver.solve(vmatrix, vrhs, velocities, res_out, iter_out);
   
   for(int j = 0; j < nj; ++j)
      for(int i = 0; i < ni+1; ++i)
         if(u_state(i,j) == FLUID)
            u(i,j) = (float)velocities[u_ind(i,j)];
         else if(u_state(i,j) == SOLID) 
            u(i,j) = u_obj;
         

   
   for(int j = 0; j < nj+1; ++j)
      for(int i = 0; i < ni; ++i)
         if(v_state(i,j) == FLUID)
            v(i,j) = (float)velocities[v_ind(i,j)];
         else if(v_state(i,j) == SOLID) 
            v(i,j) = v_obj;
}