// Result must be as large as Mesh.MaxVertexID public bool SolveMultipleCG(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) => { //PackedM.Multiply(X, B); PackedM.Multiply_Parallel(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 marginally faster 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 SolveMultipleCG(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) => { //PackedM.Multiply(X, B); PackedM.Multiply_Parallel(X, B); for (int i = 0; i < N; ++i) { B[i] += WeightsM[i, i] * X[i]; } }; List <SparseSymmetricCG> Solvers = new List <SparseSymmetricCG>(); if (SolveX) { Solvers.Add(new SparseSymmetricCG() { B = Bx, X = Sx, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }); } if (SolveY) { Solvers.Add(new SparseSymmetricCG() { B = By, X = Sy, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }); } if (SolveZ) { Solvers.Add(new SparseSymmetricCG() { B = Bz, X = Sz, MultiplyF = CombinedMultiply, PreconditionMultiplyF = Preconditioner.Multiply, UseXAsInitialGuess = true }); } bool[] ok = new bool[Solvers.Count]; gParallel.ForEach(Interval1i.Range(Solvers.Count), (i) => { ok[i] = Solvers[i].Solve(); // preconditioned solve is slower =\ //ok[i] = solvers[i].SolvePreconditioned(); }); ConvergeFailed = false; foreach (bool b in ok) { if (b == false) { ConvergeFailed = true; } } for (int i = 0; i < N; ++i) { int vid = ToCurveV[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); }