// pressure
void Fluid2::fluidPressureProjection( const float dt )
{
	if( Scene::testcase >= Scene::SMOKE )
	{
        const Vec2 dx = grid.getCellDx();
        const Vec2 invDx( 1.0f / dx.x, 1.0f / dx.y );
        const Vec2 invDxSq( 1.0f / ( dx.x * dx.x ), 1.0f / ( dx.y * dx.y ) );
        
        const Index2& size = pressure.getSize();
        const Index2& sizeu = velocityX.getSize();
        const Index2& sizev = velocityY.getSize();

        // wall boundary conditions
        for( unsigned int j = 0; j < sizeu.y; ++j )
        {
            velocityX[ Index2( 0, j ) ] = 0.0f;
            velocityX[ Index2( sizeu.x-1, j ) ] = 0.0f;
        }
        for( unsigned int i = 0; i < sizev.x; ++i )
        {
            velocityY[ Index2( i, 0 ) ] = 0.0f;
            // TOP as solid
            //velocityY[ Index2( i, sizev.y-1 ) ] = 0.0f;
        }
        
        // rhs
        const float rhoOverDt = Scene::kDensity / dt;
        std::vector< double > rhs( size.x * size.y );
		for( unsigned int i = 0; i < size.x; ++i )
		for( unsigned int j = 0; j < size.y; ++j )
        {
            const Index2 id( i, j );
            rhs[ pressure.getLinearIndex( i, j ) ] = - rhoOverDt * 
                ( ( velocityX[ Index2( i+1, j ) ] - velocityX[ id ] ) * invDx.x + 
                  ( velocityY[ Index2( i, j+1 ) ] - velocityY[ id ] ) * invDx.y );
        }
        
        // A
        SparseMatrix< double > A( size.x * size.y, 5 );
        for( unsigned int i = 0; i < size.x; ++i )
		for( unsigned int j = 0; j < size.y; ++j )
        {
            const unsigned int id = pressure.getLinearIndex( i, j );
            if( i > 0 ) {
                const unsigned int id1 = pressure.getLinearIndex( i-1, j );
                A.add_to_element( id, id, 1. * invDxSq.x );
                A.add_to_element( id, id1, -1. * invDxSq.x ); }
            if( i < size.x-1 ) {
                const unsigned int id1 = pressure.getLinearIndex( i+1, j );
                A.add_to_element( id, id, 1. * invDxSq.x );
                A.add_to_element( id, id1, -1. * invDxSq.x ); }
            if( j > 0 ) {
                const unsigned int id1 = pressure.getLinearIndex( i, j-1 );
                A.add_to_element( id, id, 1. * invDxSq.y );
                A.add_to_element( id, id1, -1. * invDxSq.y ); }
            // TOP as air
            A.add_to_element( id, id, 1. * invDxSq.y );
            if( j < size.y-1 ) {
                const unsigned int id1 = pressure.getLinearIndex( i, j+1 );
                A.add_to_element( id, id1, -1. * invDxSq.y ); }
            //// TOP as wall
            //if( j < size.y-1 ) {
            //    const unsigned int id1 = pressure.getLinearIndex( i, j+1 );
            //    A.add_to_element( id, id, 1. * invDxSq.y );
            //    A.add_to_element( id, id1, -1. * invDxSq.y ); }
        }
        
        // pcg solver
        PCGSolver< double > solver;
        solver.set_solver_parameters( 1e-6, 10000 );
        
        double residual_out;
        int iterations_out;
        std::vector< double > p( size.x * size.y );
        solver.solve( A, rhs, p, residual_out, iterations_out );
        std::cout << "Pressure system result: res=" << residual_out << ", iter=" << iterations_out << std::endl;

        // set pressure
        for( unsigned int i = 0, n = size.x * size.y; i < n; ++i )
            pressure[ i ] = (float) p[ i ];

        // apply pressure gradient
        const float dtOverRho = dt / Scene::kDensity;
		for( unsigned int i = 1; i < sizeu.x - 1; ++i )
		for( unsigned int j = 0; j < sizeu.y; ++j )
        {
            const Index2 id( i, j );
            const float gradp = ( pressure[ id ] - pressure[ Index2( i-1, j ) ] ) * invDx.x;
            velocityX[ id ] -= dtOverRho * gradp;
        }
		for( unsigned int i = 0; i < sizev.x; ++i )
		for( unsigned int j = 1; j < sizev.y - 1; ++j )
        {
            const Index2 id( i, j );
            const float gradp = ( pressure[ id ] - pressure[ Index2( i, j-1 ) ] ) * invDx.y;
            velocityY[ id ] -= dtOverRho * gradp;
        }
        // apply pressure gradient: TOP as air
        for( unsigned int i = 0; i < sizev.x; ++i )
        {
            const Index2 id( i, sizev.y-1 );
            const float gradp = ( 0.0f - pressure[ Index2( i, size.y-1 ) ] ) * invDx.y;
            velocityY[ id ] -= dtOverRho * gradp;
        }
	}
}
Example #2
0
int main(int argc, char * argv[])
{
  int gridSize = 10;
  int matSize = gridSize * gridSize;

  //only works with double
  SparseMatrixd mat(matSize);
  std::vector<double> rhs(matSize,0);
  CmpPairFirst<unsigned int, double> cmp;
  int nbr[STENCIL_SIZE][2] = {{-1,0},{0,-1},{0,1},{1,0}};
  //make a 2d laplace matrix on regular grid
  //row
  for(int ii = 0; ii<gridSize; ii++){
    //col 
    for(int jj = 0; jj<gridSize; jj++){
      int centerIdx = varIdx(ii, jj, gridSize);
      double centerVal = 0;
      std::vector<ColVal> pairs;
      int nbrCnt = 0;
      for(int nn = 0; nn<STENCIL_SIZE; nn++){
        int ni = ii + nbr[nn][0];
        int nj = jj + nbr[nn][1];
        if(inBound(ni, nj, gridSize)){
          int nbrIdx = varIdx( ni, nj, gridSize);
          nbrCnt++;
          pairs.push_back(ColVal(nbrIdx, -1));
        }
      }
      centerVal = nbrCnt;
      pairs.push_back(ColVal(centerIdx, centerVal));
      std::sort(pairs.begin(), pairs.end(), cmp);
      std::vector<unsigned int> indices(pairs.size());
      std::vector<double> values (pairs.size());
      for(unsigned int nn = 0; nn<pairs.size(); nn++){
        indices[nn] = pairs[nn].first;
        values[nn] = pairs[nn].second;
      }
      mat.add_sparse_row(centerIdx, indices, values);
      float dx = 1.0/gridSize;
      rhs[centerIdx] = dx*ii*dx*ii + dx*jj;
    }
  }
  unsigned int lastIdx = varIdx(gridSize-1, gridSize-1, gridSize);
  mat.symmetric_remove_row_and_column(lastIdx);
  mat.set_element(lastIdx, lastIdx, 1);
  rhs[lastIdx] = 0;
  mat.write_matlab(std::cout, "K");
  
  PCGSolver <double> solver;
  solver.set_solver_parameters(1e-12, 1000);
  double residual;
  int iters;
  std::vector<double> result(matSize,0);
  
  solver.solve(mat, rhs, result, residual, iters);
  
  for(unsigned int ii =0 ; ii<rhs.size(); ii++){
    std::cout<<rhs[ii]<<"\n";
  }
  for(unsigned int ii =0 ; ii<result.size(); ii++){
    std::cout<<result[ii]<<"\n";
  }
  std::cout<<"Residual: "<<residual<<"\n";
  std::cout<<"Iterations: "<<iters<<"\n";
  return 0;
}
Example #3
0
float StepperNewtonDyn::compute_dx_sparse(ElementMesh * iMesh,
                                          const std::vector<Vector3f> &iForces,
                                          const std::vector<bool> & collide,
                                          std::vector<float> &bb)
{

  bool triangular = false;
  if (!m_Init){
    iMesh->stiffnessPattern(m_I, m_J, triangular);
    int ncol = m_I.size()-1;
    mat.n = ncol;
    mat.index.resize(ncol);
    mat.value.resize(ncol);
    for (int col=0; col<ncol;col++){
      int nEntry = m_I[col+1] - m_I[col];
      mat.index[col].resize(nEntry);
      mat.value[col].resize(nEntry);
      for (int i=m_I[col]; i<m_I[col+1]; i++){
        int row = m_J[i];
        mat.index[col][ i - m_I[col] ] = row;
      }
    }
    m_Init = true;
  }

  int dim = iMesh->dim;
  int ndof = dim * iMesh->x.size();

  assert(iMesh && ndof==bb.size());

  std::vector<float> Kvalues;
  Timer timer;
  timer.start();
  iMesh->getStiffnessSparse(Kvalues, triangular, true);
  timer.end();
  std::cout<<"Assembly time "<< timer.getSeconds()<<"\n";

  timer.start();

  for(unsigned int ii = 0;ii<m->x.size(); ii++){
    for(int jj = 0;jj<dim;jj++){
      int row = dim*ii + jj;
      if(m->fixed[ii]){
        bb[ row ] = 0;
      }else{
        bb[ row ] = iForces[ii][jj];
      }
    }
  }

  int nrow = ndof;
  int ncol = ndof;

  std::vector<double> rhs(nrow);
  std::vector<double> x(nrow,0);

  for (int col=0; col<ncol;col++){
    rhs[col] = bb[col];

    for (int i=m_I[col]; i<m_I[col+1]; i++){
      int row = m_J[i];
      if(triangular && col>row){
        continue;
      }
      Kvalues[i] *= 0.5*h*h;
      int vrow = row/dim;
      if(row == col){
        Kvalues[i] += m->mass[vrow];
      }
      mat.value[col][ i-m_I[col] ] = Kvalues[i];
      if(col==row){
//       std::cout<<mat.value[col][ i-m_I[col] ]<<"\n";
      }
    }
  }

  timer.end();
  std::cout<<"Copy data time "<< timer.getSeconds()<<"\n";
  timer.start();

  //collision correction
  if(collide.size() == iMesh->x.size()){
    for (int col=0; col<ncol;col++){
      int vcol = col/dim;
      if(collide[vcol]){
        rhs[col] = 0;
      }
      for (int i=m_I[col]; i<m_I[col+1]; i++){
       int row = m_J[i];
       if(triangular && col>row){
          continue;
       }
       int vrow = row/dim;
       if(collide[vrow] || collide [vcol]){
         if(row != col){
           mat.value[col][ i-m_I[col] ]=0;
         }else{
//           std::cout<<mat.value[col][ i-m_I[col] ]<<"\n";
         }
       }
      }
    }
  }

  timer.end();
  std::cout<<"Copy collision time "<< timer.getSeconds()<<"\n";

  timer.start();
  ///@TODO add call to sparse solver
  double residual=0;
  int iters = 0;
  PCGSolver <double> solver;
  solver.set_solver_parameters(1e-6,200,0);
//  mat.write_matlab(std::cout, "K");
  bool ret = solver.solve(mat, rhs, x,residual, iters);
  std::cout<< "pcg ret " <<ret<<" iters " << iters << " residual "<<residual<<"\n";
  timer.end();

  std::cout<<"Solver time "<< timer.getSeconds()<<"\n";

  for(int ii = 0;ii<x.size();ii++){
    bb[ii] = x[ii];
  }

  return 0;
}