void crankNicolson (Ref<VectorXd> u,
                    const double delta_t,
                    const double h,
                    const double kappa) {
  const int N = sqrt(u.rows());
  static SparseMatrix<double> C;
  static SimplicialLLT<SparseMatrix<double>> Bdecomp;
  static double mu;
  static int oldN;
  if (oldN != N) {
    mu = delta_t * kappa / (h * h);
    
    vector<Triplet<double>> tripletList;
    tripletList.reserve (5 * N * N);
    tripletList.push_back (Triplet<double> (0, 0, -4 * mu));
    for (int i = 1; i < N * N; ++i) {
      tripletList.push_back (Triplet<double> (i, i, -4 * mu));
      tripletList.push_back (Triplet<double> (i, i - 1, mu));
      tripletList.push_back (Triplet<double> (i - 1, i, mu));
    }
    for (int i = 0; i < N * N - N; ++i) {
      tripletList.push_back (Triplet<double> (i, i + N, mu));
      tripletList.push_back (Triplet<double> (i + N, i, mu));
    }

    SparseMatrix<double> A (N * N, N * N);
    A.setFromTriplets (tripletList.begin (), tripletList.end ());

    SparseMatrix<double> B (N * N, N * N);
    B.setIdentity();
    B -= 0.5 * A;
    Bdecomp.compute (B);

    C.resize (N * N, N * N);
    C.setIdentity();
    C += 0.5 * A;

    oldN = N;
  }

  VectorXd rhs = C * u;

  u = Bdecomp.solve (rhs);
}
示例#2
0
void ImplicitEuler::renderNewtonsMethod(VectorXd& ext_force){
	//Implicit Code
	v_k.setZero();
	x_k.setZero();
	x_k = x_old;
	v_k = v_old;

	int ignorePastIndex = TV.rows() - fixedVerts.size();
	SparseMatrix<double> forceGradientStaticBlock;
	forceGradientStaticBlock.resize(3*ignorePastIndex, 3*ignorePastIndex);	
	
	SparseMatrix<double> RegMassBlock;
	RegMassBlock.resize(3*ignorePastIndex, 3*ignorePastIndex);
	RegMassBlock = RegMass.block(0, 0, 3*ignorePastIndex, 3*ignorePastIndex);

	forceGradient.setZero();
	bool Nan=false;
	int NEWTON_MAX = 10, i =0;
	// cout<<"--------"<<simTime<<"-------"<<endl;
	// cout<<"x_k"<<endl;
	// cout<<x_k<<endl<<endl;
	// cout<<"v_k"<<endl;
	// cout<<v_k<<endl<<endl;
	// cout<<"--------------------"<<endl;
	for( i=0; i<NEWTON_MAX; i++){
		grad_g.setZero();
		ImplicitXtoTV(x_k, TVk);//TVk value changed in function
		ImplicitCalculateElasticForceGradient(TVk, forceGradient); 
		ImplicitCalculateForces(TVk, forceGradient, x_k, f);
		f = f+ext_force;
	
		// VectorXd g_block = x_k - x_old -h*v_old -h*h*InvMass*f;
		// grad_g = Ident - h*h*InvMass*forceGradient - h*rayleighCoeff*InvMass*forceGradient;
		

		//Block forceGrad and f to exclude the fixed verts
		forceGradientStaticBlock = forceGradient.block(0,0, 3*(ignorePastIndex), 3*ignorePastIndex);
		VectorXd g = RegMass*x_k - RegMass*x_old - h*RegMass*v_old - h*h*f;
		VectorXd g_block = g.head(ignorePastIndex*3);
		grad_g = RegMassBlock - h*h*forceGradientStaticBlock - h*rayleighCoeff*forceGradientStaticBlock;

		//solve for delta x
		// Conj Grad
		// ConjugateGradient<SparseMatrix<double>> cg;
		// cg.compute(grad_g);
		// VectorXd deltaX = -1*cg.solve(g);

		// Sparse Cholesky LL^T
		SimplicialLLT<SparseMatrix<double>> llt;
		llt.compute(grad_g);
		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(g_block);
		x_k.segment(0, 3*(ignorePastIndex)) += deltaX;

		//Sparse QR 
		// SparseQR<SparseMatrix<double>, COLAMDOrdering<int>> sqr;
		// sqr.compute(grad_g);
		// VectorXd deltaX = -1*sqr.solve(g_block);
		// x_k.segment(0, 3*(ignorePastIndex)) += deltaX;

		// CholmodSimplicialLLT<SparseMatrix<double>> cholmodllt;
		// cholmodllt.compute(grad_g);
		// VectorXd deltaX = -cholmodllt.solve(g_block);

		if(x_k != x_k){
			Nan = true;
			break;
		}
		if(g_block.squaredNorm()<.00000001){
			break;
		}
	}
	if(Nan){
		cout<<"ERROR: Newton's method doesn't converge"<<endl;
		cout<<i<<endl;
		exit(0);
	}
	if(i== NEWTON_MAX){
		cout<<"ERROR: Newton max reached"<<endl;
		cout<<i<<endl;
		exit(0);
	}
	v_old.setZero();
	v_old = (x_k - x_old)/h;
	x_old = x_k;
}