void ConjugateGradientTest::test_to_XML(void)   
{
   message += "test_to_XML\n";

   ConjugateGradient cg;

   tinyxml2::XMLDocument* cgd = cg.to_XML();
   assert_true(cgd != NULL, LOG);
}
Example #2
0
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::export]]
Eigen::MatrixXd cgm_c(SEXP As, SEXP bs) {
  const MSpMat A = as<MSpMat>(As);
  //const Map<MatrixXd> A(as<Map<MatrixXd> > (As));
  const Map<MatrixXd> b(as<Map<MatrixXd> > (bs));
  ConjugateGradient<SparseMatrix<double> > cg;
  cg.setTolerance(1e-06);
  //ConjugateGradient<MatrixXd> cg;
  //cg.compute(A);
  MatrixXd x=cg.compute(A).solve(b);
  return x;
}
void ConjugateGradientTest::test_set_training_direction_method(void)
{
   message += "test_set_training_direction_method\n";

   ConjugateGradient cg;

   cg.set_training_direction_method(ConjugateGradient::FR);
   assert_true(cg.get_training_direction_method() == ConjugateGradient::FR, LOG);

   cg.set_training_direction_method(ConjugateGradient::PR);
   assert_true(cg.get_training_direction_method() == ConjugateGradient::PR, LOG);
}
void ConjugateGradientTest::test_get_training_direction_method(void)
{
   message += "test_get_training_direction_method\n";

   ConjugateGradient cg;

   cg.set_training_direction_method(ConjugateGradient::PR);

   ConjugateGradient::TrainingDirectionMethod training_direction_method = cg.get_training_direction_method();

   assert_true(training_direction_method == ConjugateGradient::PR, LOG);
}
Example #5
0
void LeastSquareFitClass::solveLeastSquareFit(MatrixXd A,
                                              VectorXd dataPoints,
                                              VectorXd *bestFit){

   VectorXd b = A.adjoint() * dataPoints;
   MatrixXd M = A.adjoint() * A;

   // Solving M x = b 
   ConjugateGradient<MatrixXd> cg;
   cg.compute(M);
   (*bestFit) = cg.solve(b);

}
int sipg_sem_1d<FLOAT_TYPE>::solve()
{

  stiffness_matrix_generation.start(); // start timer  
  compute_stiffness_matrix();
  stiffness_matrix_generation.stop();  // stop timer


  compute_rhs_vector();



#ifdef USE_LAPACK

  std::vector<int> ipiv(_vec_size,0); // pivot
  _u = _rhs;

  linear_system_solution.start(); // start timer

  int info = lapacke_gesv( LAPACK_ROW_MAJOR,
                           _vec_size,
                           1,
                            _A.data(),
                           _vec_size,
                           ipiv.data(),
                           _u.data(),
                           1                );

#else

  ConjugateGradient<Eigen::SparseMatrix<FLOAT_TYPE> > cg;
  cg.compute(_A);
  _u = cg.solve(_rhs);
 
#endif


  linear_system_solution.stop(); // stop timer 

  compute_err_norms();

  return info;

}
Example #7
0
void LeastSquareFitClass::nothing(MatrixXd A, VectorXd dataPoints){

   VectorXd b = A.adjoint() * dataPoints;
   MatrixXd M = A.adjoint() * A;

   //cout << "The matrix A is of size "
   //          << A.rows() << "x" << A.cols() << std::endl;
   //cout << "Here is the matrix b \n" << b << endl;
   //cout << "Here is the matrix M \n" << M << endl;

   // Solving M x = b 
   int n = b.size();
   VectorXd x(n);
   ConjugateGradient<MatrixXd> cg;
   cg.compute(M);
   x = cg.solve(b);
 
   //cout << "#iterations:     " << cg.iterations() << std::endl;
   //cout << "estimated error: " << cg.error()      << std::endl;
   //cout << "Final Result x = \n" << x << std::endl;

}
void ConjugateGradientTest::test_set_reserve_all_training_history(void)
{
   message += "test_set_reserve_all_training_history\n";

   ConjugateGradient cg;
   cg.set_reserve_all_training_history(true);

   assert_true(cg.get_reserve_parameters_history() == true, LOG);
   assert_true(cg.get_reserve_parameters_norm_history() == true, LOG);

   assert_true(cg.get_reserve_performance_history() == true, LOG);
   assert_true(cg.get_reserve_gradient_history() == true, LOG);
   assert_true(cg.get_reserve_gradient_norm_history() == true, LOG);

   assert_true(cg.get_reserve_training_direction_history() == true, LOG);
   assert_true(cg.get_reserve_training_rate_history() == true, LOG);
   assert_true(cg.get_reserve_elapsed_time_history() == true, LOG);
   assert_true(cg.get_reserve_generalization_performance_history() == true, LOG);
}
Example #9
0
void Simulation::staticSolveNewtonsForces(MatrixXd& TV, MatrixXi& TT, MatrixXd& B, VectorXd& fixed_forces, int ignorePastIndex){
	cout<<"----------------Static Solve Newtons, Fix Forces-------------"<<endl;
	//Newtons method static solve for minimum Strain E
	SparseMatrix<double> forceGradient;
	forceGradient.resize(3*TV.rows(), 3*TV.rows());
	SparseMatrix<double> forceGradientStaticBlock;
	forceGradientStaticBlock.resize(3*ignorePastIndex, 3*ignorePastIndex);
	VectorXd f, x;
	f.resize(3*TV.rows());
	f.setZero();
	x.resize(3*TV.rows());
	x.setZero();
	setTVtoX(x, TV);
	cout<<x<<endl;
	int NEWTON_MAX = 100, k=0;
	for(k=0; k<NEWTON_MAX; k++){
		xToTV(x, TV);

		calculateForceGradient(TV, forceGradient);
		calculateElasticForces(f, TV);
		for(unsigned int i=0; i<fixed_forces.rows(); i++){
			if(abs(fixed_forces(i))>0.000001){
				if(i>3*ignorePastIndex){
					cout<<"Problem Check simulation.cpp file"<<endl;
					cout<<ignorePastIndex<<endl;
					cout<<i<<" - "<<fixed_forces(i)<<endl;
					exit(0);
				}
				f(i) = fixed_forces(i);
			}
		}
		
		//Block forceGrad and f to exclude the fixed verts
		forceGradientStaticBlock = forceGradient.block(0,0, 3*(ignorePastIndex), 3*ignorePastIndex);
		VectorXd fblock = f.head(ignorePastIndex*3);

		//Sparse QR 
		// SparseQR<SparseMatrix<double>, COLAMDOrdering<int>> sqr;
		// sqr.compute(forceGradientStaticBlock);
		// VectorXd deltaX = -1*sqr.solve(fblock);

		// Conj Grad
		ConjugateGradient<SparseMatrix<double>> cg;
		cg.compute(forceGradientStaticBlock);
		if(cg.info() == Eigen::NumericalIssue){
			cout<<"ConjugateGradient numerical issue"<<endl;
			exit(0);
		}
		VectorXd deltaX = -1*cg.solve(fblock);

		// // Sparse Cholesky LL^T
		// SimplicialLLT<SparseMatrix<double>> llt;
		// llt.compute(forceGradientStaticBlock);
		// if(llt.info() == Eigen::NumericalIssue){
		// 	cout<<"Possibly using a non- pos def matrix in the LLT method"<<endl;
		// 	exit(0);
		// }
		// VectorXd deltaX = -1*llt.solve(fblock);

		x.segment(0,3*(ignorePastIndex))+=deltaX;
		cout<<"		Newton Iter "<<k<<endl;

		if(x != x){
			cout<<"NAN"<<endl;
			exit(0);
		}
		cout<<"fblock square norm"<<endl;
		cout<<fblock.squaredNorm()/fblock.size()<<endl;
		double strainE = 0;
		for(int i=0; i< M.tets.size(); i++){
			strainE += M.tets[i].undeformedVol*M.tets[i].energyDensity;
		}
		cout<<strainE<<endl;
		if (fblock.squaredNorm()/fblock.size() < 0.00001){
			break;
		}

	}
	if(k== NEWTON_MAX){
		cout<<"ERROR Static Solve: Newton max reached"<<endl;
		cout<<k<<endl;
		exit(0);
	}
	double strainE = 0;
	for(int i=0; i< M.tets.size(); i++){
		strainE += M.tets[i].undeformedVol*M.tets[i].energyDensity;
	}
	cout<<"strain E"<<strainE<<endl;
	cout<<"x[0] "<<x(0)<<endl;
	cout<<"x[1] "<<x(1)<<endl;
	exit(0);				

	cout<<"-------------------"<<endl;
}
Example #10
0
bool Neighbourhood::computeQuadric()
{
	//invalidate previous quadric (if any)
	m_structuresValidity &= (~FLAG_QUADRIC);

	assert(m_associatedCloud);
	if (!m_associatedCloud)
		return false;

	unsigned count = m_associatedCloud->size();
	
	assert(CC_LOCAL_MODEL_MIN_SIZE[QUADRIC] >= 5);
	if (count < CC_LOCAL_MODEL_MIN_SIZE[QUADRIC])
		return false;

	const PointCoordinateType* lsPlane = getLSPlane();
	if (!lsPlane)
		return false;

	//we get centroid (should already be up-to-date - see computeCovarianceMatrix)
	const CCVector3* G = getGravityCenter();
	assert(G);

	//get the best projection axis
	Tuple3ub idx(0/*x*/,1/*y*/,2/*z*/); //default configuration: z is the "normal" direction, we use (x,y) as the base plane
	PointCoordinateType nxx = lsPlane[0]*lsPlane[0];
	PointCoordinateType nyy = lsPlane[1]*lsPlane[1];
	PointCoordinateType nzz = lsPlane[2]*lsPlane[2];
	if (nxx > nyy)
	{
		if (nxx > nzz)
		{
			//as x is the "normal" direction, we use (y,z) as the base plane
			idx.x = 1/*y*/; idx.y = 2/*z*/; idx.z = 0/*x*/;
		}
	}
	else
	{
		if (nyy > nzz)
		{
			//as y is the "normal" direction, we use (z,x) as the base plane
			idx.x = 2/*z*/; idx.y = 0/*x*/; idx.z = 1/*y*/;
		}
	}

	//compute the A matrix and b vector
	std::vector<float> A;
	std::vector<float> b;
	try
	{
		A.resize(6*count);
		b.resize(count);
	}
	catch (std::bad_alloc)
	{
		//not enough memory
		return false;
	}

	float lmax2 = 0; //max (squared) dimension

    //for all points
	{
		float* _A = &(A[0]);
		float* _b = &(b[0]);
		for (unsigned i=0; i<count; ++i)
		{
			CCVector3 P = *m_associatedCloud->getPoint(i) - *G;

			float lX = static_cast<float>(P.u[idx.x]);
			float lY = static_cast<float>(P.u[idx.y]);
			float lZ = static_cast<float>(P.u[idx.z]);

			*_A++ = 1.0f;
			*_A++ = lX;
			*_A++ = lY;
			*_A = lX*lX;
			//by the way, we track the max 'X' squared dimension
			if (*_A > lmax2)
				lmax2 = *_A;
			++_A;
			*_A++ = lX*lY;
			*_A = lY*lY;
			//by the way, we track the max 'Y' squared dimension
			if (*_A > lmax2)
				lmax2 = *_A;
			++_A;

			*_b++ = lZ;
			lZ *= lZ;
			//and don't forget to track the max 'Z' squared dimension as well
			if (lZ > lmax2)
				lmax2 = lZ;
		}
	}

	//conjugate gradient initialization
	//we solve tA.A.X=tA.b
	ConjugateGradient<6,double> cg;
	CCLib::SquareMatrixd& tAA = cg.A();
	double* tAb = cg.b();

	//compute tA.A and tA.b
	{
		for (unsigned i=0; i<6; ++i)
		{
			//tA.A part
			for (unsigned j=i; j<6; ++j)
			{
				double tmp = 0;
				float* _Ai = &(A[i]);
				float* _Aj = &(A[j]);
				for (unsigned k=0; k<count; ++k)
				{
					//tmp += A[(6*k)+i] * A[(6*k)+j];
					tmp += static_cast<double>(*_Ai) * static_cast<double>(*_Aj);
					_Ai += 6;
					_Aj += 6;
				}
				tAA.m_values[j][i] = tAA.m_values[i][j] = tmp;
			}

			//tA.b part
			{
				double tmp = 0;
				float* _Ai = &(A[i]);
				float* _b  = &(b[i]);
				for (unsigned k=0; k<count; ++k)
				{
					//tmp += A[(6*k)+i]*b[k];
					tmp += static_cast<double>(*_Ai) * static_cast<double>(*_b++);
					_Ai += 6;
				}
				tAb[i] = tmp;
			}
		}
	}

	//first guess for X: plane equation (a0.x+a1.y+a2.z=a3 --> z = a3/a2 - a0/a2.x - a1/a2.y)
	double X0[6] = {static_cast<double>(/*lsPlane[3]/lsPlane[idx.z]*/0), //DGM: warning, points have already been recentred around the gravity center! So forget about a3
					static_cast<double>(-lsPlane[idx.x]/lsPlane[idx.z]),
					static_cast<double>(-lsPlane[idx.y]/lsPlane[idx.z]),
					0,
					0,
					0 };

	//special case: a0 = a1 = a2 = 0! //happens for perfectly flat surfaces!
	if (X0[1] == 0 && X0[2] == 0)
		X0[0] = 1.0;

	//init. conjugate gradient
	cg.initConjugateGradient(X0);

	//conjugate gradient iterations
	{
		double convergenceThreshold = lmax2 * 1.0e-8;  //max. error for convergence = 1e-8 of largest cloud dimension (empirical!)
		for (unsigned i=0; i<1500; ++i)
		{
			double lastError = cg.iterConjugateGradient(X0);
			if (lastError < convergenceThreshold) //converged
				break;
		}
	}
	//fprintf(fp,"X%i=(%f,%f,%f,%f,%f,%f)\n",i,X0[0],X0[1],X0[2],X0[3],X0[4],X0[5]);
	//fprintf(fp,"lastError=%E/%E\n",lastError,convergenceThreshold);
	//fclose(fp);

	//output
	{
		for (unsigned i=0; i<6; ++i)
		{
			m_quadricEquation[i] = static_cast<PointCoordinateType>(X0[i]);
		}
		m_quadricEquationDirections = idx;

		m_structuresValidity |= FLAG_QUADRIC;
	}

	return true;
}
Example #11
0
bool Neighbourhood::computeHeightFunction()
{
	//invalidate previous quadric (if any)
	structuresValidity &= (~HEIGHT_FUNCTION);

	assert(m_associatedCloud);
	if (!m_associatedCloud)
		return false;

	unsigned count = m_associatedCloud->size();
	
	assert(CC_LOCAL_MODEL_MIN_SIZE[HF] >= 5);
	if (count < CC_LOCAL_MODEL_MIN_SIZE[HF])
		return false;

	const PointCoordinateType* lsq = getLSQPlane();
	if (!lsq)
        return false;

	//we get centroid (should already be up-to-date - see computeCovarianceMatrix)
	const CCVector3* G = getGravityCenter();
	assert(G);

	//get the best projection axis
	uchar idx_X=0/*x*/,idx_Y=1/*y*/,idx_Z=2/*z*/; //default configuration: z is the "normal" direction, we use (x,y) as the base plane
	PointCoordinateType nxx = lsq[0]*lsq[0];
	PointCoordinateType nyy = lsq[1]*lsq[1];
	PointCoordinateType nzz = lsq[2]*lsq[2];
	if (nxx > nyy)
	{
		if (nxx > nzz)
		{
			//as x is the "normal" direction, we use (y,z) as the base plane
			idx_X=1/*y*/; idx_Y=2/*z*/; idx_Z=0/*x*/;
		}
	}
	else
	{
	    if (nyy > nzz)
		{
			//as y is the "normal" direction, we use (z,x) as the base plane
			idx_X=2/*z*/; idx_Y=0/*x*/; idx_Z=1/*y*/;
		}
    }

	//compute the A matrix and b vector
	float *A = new float[6*count];
	float *b = new float[count];

	float lmax2=0; //max (squared) dimension

    //for all points
	{
		float* _A=A;
		float* _b=b;
		for (unsigned i=0;i<count;++i)
		{
			CCVector3 P = *m_associatedCloud->getPoint(i) - *G;

			float lX = (float)P.u[idx_X];
			float lY = (float)P.u[idx_Y];
			float lZ = (float)P.u[idx_Z];

			*_A++ = 1.0;
			*_A++ = lX;
			*_A++ = lY;
			*_A = lX*lX;
			//by the way, we track the max 'X' squared dimension
			if (*_A>lmax2)
				lmax2=*_A;
			++_A;
			*_A++ = lX*lY;
			*_A = lY*lY;
			//by the way, we track the max 'Y' squared dimension
			if (*_A>lmax2)
				lmax2=*_A;
			++_A;

			*_b++ = lZ;
			lZ *= lZ;
			//and don't forget to track the max 'Z' squared dimension as well
			if (lZ>lmax2)
				lmax2=lZ;
		}
	}

	//conjugate gradient initialization
	//we solve tA.A.X=tA.b
	ConjugateGradient<6,double> cg;
	CCLib::SquareMatrixd& tAA = cg.A();
	double* tAb = cg.b();

	//compute tA.A and tA.b
	{
		for (unsigned i=0; i<6; ++i)
		{
			//tA.A part
			for (unsigned j=i; j<6; ++j)
			{
				double tmp = 0;
				float* _Ai = A+i;
				float* _Aj = A+j;
				for (unsigned k=0; k<count; ++k)
				{
					//tmp += A[(6*k)+i]*A[(6*k)+j];
					tmp += (double)((*_Ai) * (*_Aj));
					_Ai += 6;
					_Aj += 6;
				}
				tAA.m_values[j][i] = tAA.m_values[i][j] = tmp;
			}

			//tA.b part
			{
				double tmp = 0;
				float* _Ai = A+i;
				float* _b = b;
				for (unsigned k=0; k<count; ++k)
				{
					//tmp += A[(6*k)+i]*b[k];
					tmp += (double)((*_Ai) * (*_b++));
					_Ai += 6;
				}
				tAb[i] = tmp;
			}
		}
	}

	//first guess for X: plane equation (a0.x+a1.y+a2.z=a3 --> z = a3/a2 - a0/a2.x - a1/a2.y)
	double X0[6];
	X0[0] = (double)/*lsq[3]/lsq[idx_Z]*/0; //DGM: warning, points have already been recentred around the gravity center! So forget about a3
	X0[1] = (double)(-lsq[idx_X]/lsq[idx_Z]);
	X0[2] = (double)(-lsq[idx_Y]/lsq[idx_Z]);
	X0[3] = 0;
	X0[4] = 0;
	X0[5] = 0;

	//special case: a0 = a1 = a2 = 0! //happens for perfectly flat surfaces!
	if (X0[1] == 0.0 && X0[2] == 0.0)
		X0[0] = 1.0;

	//init. conjugate gradient
	cg.initConjugateGradient(X0);

    //conjugate gradient iterations
	{
		double convergenceThreshold = (double)lmax2 * 1e-8;  //max. error for convergence = 1e-8 of largest cloud dimension (empirical!)
		for (unsigned i=0; i<1500; ++i)
		{
			double lastError = cg.iterConjugateGradient(X0);
			if (lastError < convergenceThreshold) //converged
				break;
		}
	}
	//fprintf(fp,"X%i=(%f,%f,%f,%f,%f,%f)\n",i,X0[0],X0[1],X0[2],X0[3],X0[4],X0[5]);
	//fprintf(fp,"lastError=%E/%E\n",lastError,convergenceThreshold);
	//fclose(fp);

	delete[] A;
	A=0;
	delete[] b;
	b=0;

	//output
	{
		for (unsigned i=0;i<6;++i)
			theHeightFunction[i]=(PointCoordinateType)X0[i];
		theHeightFunctionDirections[0]=idx_X;
		theHeightFunctionDirections[1]=idx_Y;
		theHeightFunctionDirections[2]=idx_Z;

		structuresValidity |= HEIGHT_FUNCTION;
	}

	return true;
}
Example #12
0
void Gelatin::step(double h, const Vector3d &grav, const vector< shared_ptr<FreakFace> > faces)
{
	aTrips.clear();
	//v.setZero();
	//f.setZero();
//
//	vTrips.clear();
//    fTrips.clear();

    VectorXd b(n);
    b.setZero();

	for (int i = 0; i < particles.size(); i++) {
	    if (!particles[i]->fixed) {
	        int index = particles[i]->i;
	        double m = particles[i]->m;

	        double val = m + h * damping(0) * m;
            aTrips.push_back(Trip(index, index, val));
            aTrips.push_back(Trip(index+1, index+1, val));
            aTrips.push_back(Trip(index+2, index+2, val));

            Vector3d v = particles[i]->v;
            Vector3d fg = h * m * grav;
            b(index) = m * v(0) + fg(0);
            b(index+1) = m * v(1) + fg(1);
            b(index+2) = m * v(2) + fg(2);
        }
	}

	for (int i = 0; i < springs.size(); i++) {
	    double E = springs[i]->E;
	    double L = springs[i]->L;
	    auto p0 = springs[i]->p0;
	    auto p1 = springs[i]->p1;

	    //MatrixXd delta(3, 1);
        Vector3d delta = p1->x - p0->x;
	    double l = delta.norm();

	    Vector3d fs = E * (l - L) * (delta / l);

	    if (!springs[i]->p0->fixed) {
	        b(p0->i) += h * fs(0);
	        b(p0->i+1) += h * fs(1);
	        b(p0->i+2) += h * fs(2);
	    }
	    if (!springs[i]->p1->fixed) {
	        b(p1->i) -= h * fs(0);
            b(p1->i+1) -= h * fs(1);
            b(p1->i+2) -= h * fs(2);
	    }

        if (!springs[i]->p0->fixed && !springs[i]->p1->fixed) {
            Matrix3d ks =  (E / (l * l)) * ((1.0 - (l - L)/l) * (delta * delta.transpose())
                + ((l - L)/l) * double(delta.transpose() * delta) * Matrix3d::Identity());
            int i0 = p0->i;
            int i1 = p1->i;

            addKs(ks, i0, i1, h);
        }
	}

    Eigen::SparseMatrix<double> sparseA(n,n);
    sparseA.setFromTriplets(aTrips.begin(), aTrips.end());

    ConjugateGradient< SparseMatrix<double> > cg;
    cg.setMaxIterations(25);
    cg.setTolerance(1e-3);
    cg.compute(sparseA);

    //v = cg.solve(b);
    v = cg.solveWithGuess(b, v);

	//v = A.ldlt().solve(b);

	for (int i = 0; i < particles.size(); i++) {
	    if (!particles[i]->fixed) {
            int index = particles[i]->i;
            particles[i]->v = v.block<3,1>(index, 0);
            particles[i]->x += h * particles[i]->v;
        }
	}

	collide(faces);

	// Update position and normal buffers
	updatePosNor();
}
Example #13
0
void FluidSolver::pressureSolve(float timeStepSec)
{
  // NOTE: assumptions are made here that the only "SOLID" cells in the sim
  // are the walls of the simulation, and are therefore not handled in this
  // method.  Instead, they are handled in the boundaryCollide method where
  // velocities entering or exiting a boundary are simply set to 0.0f.

  // The pressureSolve routine does the following:
  // * Calculate the negative divergence b with moditications at solid walls.
  // * Set the entries of A (stored in Adiag, etc.)
  // * Solve the Ap = b using the conjugate gradient algorithm.
  // * Compute the new velocities according to the updated pressure.

  // Calculate the dimensionality of our vectors/matrix.
  const unsigned width  = _grid.getColCount() - 1;
  const unsigned height = _grid.getRowCount() - 1;
  int dim = width * height;

  // Calculate the negative divergence throughout the simulation.
  VectorXd b(dim);
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      unsigned index = y * width + x;
      b(index) = -_grid.getVelocityDivergence(x, y);
    }

  // Update the negative divergence to account for solid boundaries.
  // TODO assumes that the only solids are at the boundaries, which have 0 vel.
  // Bottom row.
  for (unsigned x = 0; x < width; ++x) {
    unsigned y = 0;
    unsigned index = y * width + x;
    b(index) -= _grid(x,y).vel[Cell::Y];
  }
  // Top row.
  for (unsigned x = 0; x < width; ++x) {
    unsigned y = height - 1;
    unsigned index = y * width + x;
    b(index) += _grid(x,y+1).vel[Cell::Y];
  }
  // Left column.
  for (unsigned y = 0; y < height; ++y) {
    unsigned x = 0;
    unsigned index = y * width + x;
    b(index) -= _grid(x,y).vel[Cell::X];
  }
  // Right column.
  for (unsigned y = 0; y < height; ++y) {
    unsigned x = width - 1;
    unsigned index = y * width + x;
    b(index) += _grid(x+1,y).vel[Cell::X];
  }

  // Enforce the compatibility condition.
  // TODO don't need this if we have a free surface.
  /*
  double mean = 0.0;
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      unsigned index = y * width + x;
      mean += b(index);
    }
  //  std::cout.precision(15);
  //  std::cout << "Overall Divergence: " << mean << std::endl;
  mean /= dim;
  //  std::cout << "PerEntry Divergence: " << mean << std::endl;
  //  std::cout << "Pre-compat Divergence: " << std::endl << b << std::endl;
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      unsigned index = y * width + x;
      b(index) -= mean;
    }
  //  std::cout << "Post-compat Divergence: " << std::endl << b << std::endl;
  */

  // Set the entries of A. 
  std::vector< Tripletd > vals;
  SparseMatrix<double,RowMajor> A(dim, dim);
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      Cell &cell = _grid(x,y);
      unsigned i = y * width + x;  // this cell's col/row in A.
      unsigned j;                  // neighbor cell's col/row in A

      switch (cell.cellType) {
      case (Cell::SOLID):
	// If this cell is a SOLID, leave the entire row as 0's.
	break;

      case (Cell::AIR):
	// If this cell is AIR, increment neighboring fluid diagonals' coeff.
	if (cell.neighbors[Cell::POS_X]->cellType == Cell::FLUID) {
	  j = y * width + x + 1;                        // rt neighbor's idx
	  vals.push_back( Tripletd(j,j,timeStepSec) );  // rt neighbor's diag
	}
	if (cell.neighbors[Cell::POS_Y]->cellType == Cell::FLUID) {
	  j = (y + 1) * width + x;                      // up neighbor's idx
	  vals.push_back( Tripletd(j,j,timeStepSec) );  // up neighbor's diag
	}
	break;

      case (Cell::FLUID):
	// Cell is fluid. Determine coefficients of self and neighbors.
	if (cell.neighbors[Cell::POS_X]->cellType == Cell::FLUID) {
	  j = y * width + x + 1;                        // rt neighbor's idx
	  vals.push_back( Tripletd(i,i,timeStepSec) );  // my diagonal coeff
	  vals.push_back( Tripletd(i,j,-timeStepSec) ); // rt neighbor's coeff
	  vals.push_back( Tripletd(j,j,timeStepSec) );  // rt neighbor's diag
	}
	else if (cell.neighbors[Cell::POS_X]->cellType == Cell::AIR) {
	  vals.push_back( Tripletd(i,i,timeStepSec) );
	}
	if (cell.neighbors[Cell::POS_Y]->cellType == Cell::FLUID) {
	  j = (y + 1) * width + x;                      // up neighbor's idx
	  vals.push_back( Tripletd(i,i,timeStepSec) );  // my diagonal coeff
	  vals.push_back( Tripletd(i,j,-timeStepSec) ); // up neighbor's coeff
	  vals.push_back( Tripletd(j,j,timeStepSec) );  // up neighbor's diag
	}
	else if (cell.neighbors[Cell::POS_Y]->cellType == Cell::AIR) {
	  vals.push_back( Tripletd(i,i,timeStepSec) );
	}
	break;
	
      default:
	break;
      }
    }
  A.setFromTriplets(vals.begin(), vals.end());

  // Solve for the new pressure values, p.
  VectorXd p(dim);
  ConjugateGradient< SparseMatrix<double,RowMajor> > cg;
  cg.compute(A);
  p = cg.solve(b);
  if (cg.info() == Success)
    std::cout << "SUCCESS: Convergence!" << std::endl;
  else 
    std::cout << "FAILED: No Convergence..." << std::endl;
  //  std::cout << "#iterations:     " << cg.iterations() << std::endl;
  //  std::cout << "estimated error: " << cg.error()      << std::endl;  
  //  std::cout << "A: " << std::endl << A << std::endl;
  //  std::cout << "Pressure: " << std::endl << p << std::endl;
  //  std::cout << "Divergence: " << std::endl << b << std::endl;
  //  std::cout << "Ap: " << std::endl << A*p << std::endl;

  // Set new pressure values.
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      unsigned index = y * width + x;
      _grid(x, y).pressure = p(index);
    }

  // Modify velocity field based on updated pressure scalar field.
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      Cell &cell = _grid(x,y);
      float pressureVel = timeStepSec * cell.pressure;
      if (cell.cellType == Cell::FLUID) {
	// Update all neighboring velocities touched by this pressure.
	cell.vel[Cell::X] -= pressureVel;
	cell.vel[Cell::Y] -= pressureVel;
	if (cell.neighbors[Cell::POS_X])
	  cell.neighbors[Cell::POS_X]->vel[Cell::X] += pressureVel;
	if (cell.neighbors[Cell::POS_Y])
	  cell.neighbors[Cell::POS_Y]->vel[Cell::Y] += pressureVel;
      }
    }

  // Calculate the negative divergence throughout the simulation.
  for (unsigned y = 0; y < height; ++y)
    for (unsigned x = 0; x < width; ++x) {
      unsigned index = y * width + x;
      b(index) = -_grid.getVelocityDivergence(x, y);
    }
  std::cout << "New Divergence: " << std::endl << b << std::endl;
}
void DiffusionSolverFE_CPU_Implicit::Implicit(ConcentrationField_t const &concentrationField, DiffusionData const &diffData, 
	EigenRealVector const &b, EigenRealVector &x){
	size_t totalSize=(fieldDim.x+2)*(fieldDim.y+2)*(fieldDim.z+2);
	size_t totalExtSize=h_celltype_field->getArraySize();

	cerr<<"Field size: "<<totalSize<<"; total size: "<<totalExtSize<<endl;

	
	//SparseMatrix<float, RowMajor> eigenM(totalSize,totalSize);
	//float s=1;

	bool const is2D=(fieldDim.z==1);

	int neighbours=is2D?4:6;
	 
	//LARGE_INTEGER tb, te, fq;
	//QueryPerformanceFrequency(&fq);

	EigenSparseMatrix eigenM_new(totalSize,totalSize);
	//QueryPerformanceCounter(&tb);
	eigenM_new.reserve(totalSize*is2D?5:7);
	cout<<"Assembling matrix... ";
	int prevZ=-1;

	//TODO: unify this with OpenCL matrix assembling...
	for(size_t i=0; i<totalSize; ++i)//TODO: 2D simultaions can be arranged more effective, I guess...
	{
		
		int z=i/((fieldDim.x+2)*(fieldDim.y+2));
		int remz=i%((fieldDim.x+2)*(fieldDim.y+2));

		eigenM_new.startVec(i);

		int y=remz/(fieldDim.x+2);
		int x=remz%(fieldDim.x+2);

		//unsigned char currentCellType=h_celltype_field->getDirect(x+1,y+1,z+1);
		unsigned char currentCellType=h_celltype_field->getByIndex(i);
		float currentDiffCoef=diffData.diffCoef[currentCellType];//*(diffData.deltaT)/(deltaX*deltaX);
	
		int lastJ=-1;
		if(!is2D&&z>0){
			int j=flatExtInd(x,y,z-1, fieldDim);
			lastJ=j;
			//ASSERT_OR_THROW("wrong order", j<(int)i);
			//ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}
		if(y>0){
			int j=flatExtInd(x,y-1,z, fieldDim);
		//	ASSERT_OR_THROW("wrong order 1", j>lastJ);
		//	ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			lastJ=j;
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}

		if(x>0){
			int j=flatExtInd(x-1,y,z, fieldDim);
		//	ASSERT_OR_THROW("wrong order 2", j>lastJ);
		//	ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			lastJ=j;
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}

		//ASSERT_OR_THROW("wrong order 3", (int)i>lastJ);
		lastJ=i;
		eigenM_new.insertBack(i,i)=1+neighbours*currentDiffCoef;

		if(x<fieldDim.x-1){
			int j=flatExtInd(x+1,y,z, fieldDim);
		//	ASSERT_OR_THROW("wrong order 4", j>lastJ);
		//	ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			lastJ=j;
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}

		if(y<fieldDim.y-1){
			int j=flatExtInd(x,y+1,z, fieldDim);
		//	ASSERT_OR_THROW("wrong order 5", j>lastJ);
		//	ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			lastJ=j;
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}

		if(!is2D&&z<fieldDim.z-1){
			int j=flatExtInd(x,y,z+1, fieldDim);
			//ASSERT_OR_THROW("wrong order 6", j>lastJ);
			//ASSERT_OR_THROW("wrong index", j<(int)totalSize);
			lastJ=j;
			eigenM_new.insertBack(i,j)=-currentDiffCoef;
		}

	}

	cout<<"done"<<endl;
	eigenM_new.finalize();
	eigenM_new.makeCompressed();  
//	QueryPerformanceCounter(&te);
	//cout<<"completelly done"<<endl;

//	double time=(double)(te.QuadPart-tb.QuadPart)/(double)fq.QuadPart;
//	std::cerr<<"It took "<<time<<" s to assemble a matrix with new algorithm\n";

//	CompareMatrices(eigenM, eigenM_new);

//	SparseMatrix<float,RowMajor> eigenM(eigenDynM);

	
	ConjugateGradient<EigenSparseMatrix> cg;

	cout<<"Preparing system... ";
//	QueryPerformanceCounter(&tb);
	cg.compute(eigenM_new);
//	QueryPerformanceCounter(&te);
	cout<<"done"<<endl;

//	double timePrep=(double)(te.QuadPart-tb.QuadPart)/(double)fq.QuadPart;

	cout<<"Solving system... ";
//	QueryPerformanceCounter(&tb);
	x = cg.solve(b);
	//QueryPerformanceCounter(&te);
	cout<<"done"<<endl;
	
	//time=(double)(te.QuadPart-tb.QuadPart)/(double)fq.QuadPart;
	//std::cerr<<"It took "<<time<<" s to find the solution with explicit solver and "<<timePrep<<" for preparing the system\n";

	std::cout << "#iterations:     " << cg.iterations() << std::endl;
	std::cout << "estimated error: " << cg.error()      << std::endl; 
}