// 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; } } }
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; }
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; }