// Result must be as large as Mesh.MaxVertexID public bool Solve(Vector3d[] Result) { if (WeightsM == null) { Initialize(); // force initialize... } UpdateForSolve(); // use initial positions as initial solution. Array.Copy(Px, Sx, N); Array.Copy(Py, Sy, N); Array.Copy(Pz, Sz, N); Action <double[], double[]> CombinedMultiply = (X, B) => { // packed multiply is 3-4x faster... //M.Multiply(X, B); PackedM.Multiply(X, B); for (int i = 0; i < N; ++i) { B[i] += WeightsM.D[i] * X[i]; } }; SparseSymmetricCG SolverX = new SparseSymmetricCG() { B = Bx, X = Sx, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverY = new SparseSymmetricCG() { B = By, X = Sy, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverZ = new SparseSymmetricCG() { B = Bz, X = Sz, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG[] solvers = new SparseSymmetricCG[3] { SolverX, SolverY, SolverZ }; bool[] ok = new bool[3]; int[] indices = new int[3] { 0, 1, 2 }; // preconditioned solve is slower =\ //Action<int> SolveF = (i) => { ok[i] = solvers[i].SolvePreconditioned(); }; Action <int> SolveF = (i) => { ok[i] = solvers[i].Solve(); }; gParallel.ForEach(indices, SolveF); if (ok[0] == false || ok[1] == false || ok[2] == false) { return(false); } for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Result[vid] = new Vector3d(Sx[i], Sy[i], Sz[i]); } // apply post-fixed constraints if (HavePostFixedConstraints) { foreach (var constraint in SoftConstraints) { if (constraint.Value.PostFix) { int vid = constraint.Key; Result[vid] = constraint.Value.Position; } } } return(true); }
// Result must be as large as Mesh.MaxVertexID public bool Solve(Vector3d[] Result) { UpdateForSolve(); // use initial positions as initial solution. Array.Copy(Px, Sx, N); Array.Copy(Py, Sy, N); Array.Copy(Pz, Sz, N); Action <double[], double[]> CombinedMultiply = (X, B) => { M.Multiply(X, B); for (int i = 0; i < N; ++i) { B[i] += WeightsM[i, i] * X[i]; } }; SparseSymmetricCG SolverX = new SparseSymmetricCG() { B = Bx, X = Sx, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverY = new SparseSymmetricCG() { B = By, X = Sy, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG SolverZ = new SparseSymmetricCG() { B = Bz, X = Sz, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }; SparseSymmetricCG[] solvers = new SparseSymmetricCG[3] { SolverX, SolverY, SolverZ }; bool[] ok = new bool[3]; int[] indices = new int[3] { 0, 1, 2 }; Action <int> SolveF = (i) => { ok[i] = solvers[i].Solve(); }; gParallel.ForEach(indices, SolveF); if (ok[0] == false || ok[1] == false || ok[2] == false) { return(false); } for (int i = 0; i < N; ++i) { int vid = ToMeshV[i]; Result[vid] = new Vector3d(Sx[i], Sy[i], Sz[i]); } return(true); }