/// <summary> /// This is the main solver, it is running on it own thread. /// Inside this solver it /// 1. initialize the stencil matrix (only once) for the diffusion solve of the operator splitting /// 2. there is a for-loop which is controled by <c>i</c> /// 3. Inside the for-loop we do the diffusion solve first, then reaction solve, and then updated the state ODEs /// We make the following definitions: \n ///\f[A(V):=\frac{a}{2RC}\frac{\partial ^ 2V}{\partial x^2}\f] \n ///\f[r(V):= -\frac{\bar{ g} _{ K} }{ C}n ^ 4(V - V_k) -\frac{\bar{ g} _{ Na} }{ C}m ^ 3h(V - V_{ Na})-\frac{\bar{ g} _l}{ C} (V - V_l)\f] \n /// then we solve in two separate steps \n ///\f[\frac{dV}{dt}=A(V)+r(V),\f] \n /// where \f$A(V)\f$ is the second order differential operator on \f$V\f$ and \f$r(V)\f$ is the reaction part. /// We employ a Lie Splitting by first solving \n /// \f[\frac{ dV ^ *}{ dt}= A(V ^ *)\f] \n /// with initial conditions \f$V_0^*=V(t_n)= V_n\f$ at the beginning of the time step to get the intermediate solution \f$V^*\f$ /// Then we solve \f$\frac{dV^{**}}{dt}=r(V^{**})\f$ with initial condition \f$V_0^{**}=V^*\f$ to get \f$V^{**}\f$, and \f$V_{n+1}=V(t_{n+1})=V^{**}\f$ the voltage at the end of the time step. /// For equation the diffusion we use a Crank-Nicolson scheme /// </summary> /// //tex: //$$A(V):=\frac{a}{2RC}\frac{\partial ^ 2V}{\partial x^2}$$ //$$r(V):= -\frac{\bar{ g} _{ K} }{ C}n ^ 4(V - V_k) -\frac{\bar{ g} _{ Na} }{ C}m ^ 3h(V - V_{ Na})-\frac{\bar{ g} _l}{ C} (V - V_l)$$ // then we solve in two separate steps //$$\frac{dV}{dt}=A(V)+r(V),$$ //where $A(V)$ is the second order differential operator on $V$ and $r(V)$ is the reaction term on $V$. We employ a Lie Splitting by first solving //$$\frac{ dV ^ *}{ dt}= A(V ^ *)$$ //with initial condition $V_0^*=V(t_n)= V_n$ at the beginning of the time step to get the intermediate solution $V^*$. Then we solve //$\frac{dV^{**}}{dt}=r(V^{**})$ with initial condition $V_0^{**}=V^*$ to get $V^{**}$, and $V_{n+1}=V(t_{n+1})=V^{**}$ the voltage at the end of the time step. //For equation the diffusion we use a Crank-Nicolson scheme protected override void SolveStep(int t) { ///<c>if ((i * k >= 0.015) && SomaOn) { U[0] = vstart; }</c> this checks of the somaclamp is on and sets the soma location to <c>vstart</c> ///if ((t * k >= 0.015) && SomaOn) { U[0] = vstart; } ///This part does the diffusion solve \n /// <c>r_csc.Multiply(U.ToArray(), b);</c> the performs the RHS*Ucurr and stores it in <c>b</c> \n /// <c>lu.Solve(b, b);</c> this does the forward/backward substitution of the LU solve and sovles LHS = b \n /// <c>U.SetSubVector(0, Neuron.vertCount, Vector.Build.DenseOfArray(b));</c> this sets the U vector to the voltage at the end of the diffusion solve r_csc.Multiply(U.ToArray(), b); lu.Solve(b, b); U.SetSubVector(0, Neuron.nodes.Count, Vector.Build.DenseOfArray(b)); /// this part solves the reaction portion of the operator splitting \n /// <c>R.SetSubVector(0, Neuron.vertCount, reactF(reactConst, U, N, M, H, cap));</c> this first evaluates at the reaction function \f$r(V)\f$ \n /// <c>R.Multiply(k, R); </c> this multiplies by the time step size \n /// <c>U.add(R,U)</c> adds it back to U to finish off the operator splitting /// For the reaction solve we are solving /// \f[\frac{U_{next}-U_{curr}}{k} = R(U_{curr})\f] R.SetSubVector(0, Neuron.nodes.Count, reactF(reactConst, U, N, M, H, cap)); R.Multiply(timeStep, R); U.Add(R, U); /// this part solve the state variables using Forward Euler /// the general rule is \f$N_{next} = N_{curr}+k\cdot f_N(U_{curr},N_{curr})\f$ N.Add(fN(U, N).Multiply(timeStep), N); M.Add(fM(U, M).Multiply(timeStep), M); H.Add(fH(U, H).Multiply(timeStep), H); ///<c>if ((i * k >= 0.015) && SomaOn) { U[0] = vstart; }</c> this checks of the somaclamp is on and sets the soma location to <c>vstart</c> ///if ((t * k >= 0.015) && SomaOn) { U[0] = vstart; } }
public static Vector SolveLU(CompressedColumnStorage <double> A, Vector x, Vector b, out bool status, out string algorithm) { var orderings = new[] { CSparse.ColumnOrdering.MinimumDegreeAtPlusA, CSparse.ColumnOrdering.MinimumDegreeAtA, CSparse.ColumnOrdering.MinimumDegreeStS, CSparse.ColumnOrdering.Natural }; status = false; algorithm = "LU"; try { status = true; if (A.RowCount == A.ColumnCount) { var lu = new SparseLU(A, CSparse.ColumnOrdering.MinimumDegreeAtA, 1.0); var xc = x.Clone(); var bc = b.Clone(); lu.Solve(bc.ToDouble(), xc.ToDouble()); algorithm = "LU/" + CSparse.ColumnOrdering.MinimumDegreeAtPlusA; status = true; return(xc); } } catch (Exception e) { status = false; } return(x); }
public void mosek2(List<leaf> _listLeaf, List<branch> _listBranch, List<node> _listNode, double force) { //variable settings ShoNS.Array.SparseDoubleArray mat = new SparseDoubleArray(_listNode.Count * 3, _listNode.Count * 3); ShoNS.Array.SparseDoubleArray F = new SparseDoubleArray(_listNode.Count * 3, 1); ShoNS.Array.SparseDoubleArray xx = new SparseDoubleArray(_listNode.Count*3,1); ShoNS.Array.SparseDoubleArray shift = new SparseDoubleArray(_listNode.Count*3, _listNode.Count*3); for (int k = 0; k < _listNode.Count;k++ ) { var node = _listNode[k]; xx[k * 3 + 0, 0] = node.x; xx[k * 3 + 1, 0] = node.y; xx[k * 3 + 2, 0] = node.z; /* if (node.nodeType == node.type.fx) { for (int i = 0; i < node.shareB.Count; i++) { var branch = node.shareB[i]; var index = node.numberB[i]; if (branch.branchType == branch.type.fix) { node.x = branch.crv.Points[index].Location.X; node.y = branch.crv.Points[index].Location.Y; node.z = branch.slice2.height; xx[k * 3 + 0, 0] = node.x; xx[k * 3 + 1, 0] = node.y; xx[k * 3 + 2, 0] = node.z; } } }*/ } List<int> series=new List<int>(); List<Point3d> origin = new List<Point3d>(); for(int i=0;i<_listNode.Count;i++) { series.Add(i); } int L1=0; int L2=_listNode.Count; for(int i=0;i<_listNode.Count;i++) { var node=_listNode[i]; if(node.nodeType==node.type.fx) { L2--; series[i]=L2; }else{ series[i]=L1; origin.Add(new Point3d(node.x, node.y, node.z)); L1++; } } for (int i = 0; i < _listNode.Count; i++) { shift[i * 3 + 0, series[i] * 3 + 0] = 1; shift[i * 3 + 1, series[i] * 3 + 1] = 1; shift[i * 3 + 2, series[i] * 3 + 2] = 1; F[i * 3 + 2, 0] = -force;//force } foreach (var leaf in _listLeaf) { foreach (var tup in leaf.tuples) { var det = tup.SPK[0, 0] * tup.SPK[1, 1] - tup.SPK[0, 1] * tup.SPK[0, 1]; if (det > 0) { for (int i = 0; i < tup.nNode; i++) { for (int j = 0; j < tup.nNode; j++) { for (int k = 0; k < 3; k++) { for (int l = 0; l < 2; l++) { for (int m = 0; m < 2; m++) { var val = tup.B[l, m, i * 3 + k, j * 3 + k] * tup.SPK[l, m] * tup.refDv * tup.area; mat[leaf.globalIndex[tup.internalIndex[i]] * 3 + k, leaf.globalIndex[tup.internalIndex[j]] * 3 + k] += val; } } } } } } } } foreach (var branch in _listBranch) { foreach (var tup in branch.tuples) { for (int i = 0; i < tup.nNode; i++) { for (int j = 0; j < tup.nNode; j++) { for (int k = 0; k < 3; k++) { //if (tup.SPK[0, 0] > 0) { var val = tup.B[0, 0, i * 3 + k, j * 3 + k] * tup.SPK[0, 0] * tup.refDv * tup.area; for (int l = 0; l < 1; l++) { for (int m = 0; m < 1; m++) { var val2 = tup.B[l, m, i * 3 + k, j * 3 + k] * tup.SPK[l, m] * tup.refDv * tup.area; mat[branch.globalIndex[tup.internalIndex[i]] * 3 + k, branch.globalIndex[tup.internalIndex[j]] * 3 + k] += val2; } } } } } } } } var reactionForce = mat * xx as SparseDoubleArray; double max1 = 0; double max2 = 0; for (int i = 0; i < _listNode.Count; i++) { if (_listNode[i].nodeType == node.type.fr) { var nx = reactionForce[i * 3 + 0, 0]; var ny = reactionForce[i * 3 + 1, 0]; var norm = Math.Sqrt(nx * nx + ny * ny); if (norm > max1) max1 = norm; } else { var nx = reactionForce[i * 3 + 0, 0]; var ny = reactionForce[i * 3 + 1, 0]; var norm = Math.Sqrt(nx * nx + ny * ny); if (norm > max2) max2 = norm; } } //System.Windows.Forms.MessageBox.Show(max1.ToString() + ".-." + max2.ToString()); var newMat = (shift.T.Multiply(mat) as SparseDoubleArray).Multiply(shift) as SparseDoubleArray; var newxx = shift.T.Multiply(xx) as SparseDoubleArray; var newF = shift.T.Multiply(F) as SparseDoubleArray; var T = newMat.GetSliceDeep(0, L1 * 3 - 1, 0, L1 * 3 - 1); var D = newMat.GetSliceDeep(0, L1 * 3 - 1, L1 * 3, _listNode.Count * 3 - 1); var fx = newxx.GetSliceDeep(L1 * 3, _listNode.Count * 3 - 1, 0, 0); newF = newF.GetSliceDeep(0, L1 * 3 - 1, 0, 0); var solve = new SparseLU(T); //var solve = new SparseSVD(T); //var _U = solve.U; //var _V = solve.V; //var _D = solve.D; //double tol=0.00000000001; //for (int i = 0; i < L1*3; i++) //{ // if (_D[i, i] > tol) _D[i, i] = 1d / _D[i, i]; // else if (_D[i, i] < -tol) _D[i, i] = 1d / _D[i, i]; // else _D[i, i] = 0d; //} var df = D * fx as SparseDoubleArray; var b = DoubleArray.From((-newF - df)); var sol=solve.Solve(b); //var sol = _V * _D * _U.T*b; var exSol = new SparseDoubleArray(sol.GetLength(0)+fx.GetLength(0),1); for (int i = 0; i < L1; i++) { exSol[i * 3 + 0, 0] = sol[i * 3 + 0, 0]; exSol[i * 3 + 1, 0] = sol[i * 3 + 1, 0]; exSol[i * 3 + 2, 0] = sol[i * 3 + 2, 0]; } for (int i = L1; i < _listNode.Count; i++) { exSol[i * 3 + 0, 0] = fx[(i - L1) * 3 + 0, 0]; exSol[i * 3 + 1, 0] = fx[(i - L1) * 3 + 1, 0]; exSol[i * 3 + 2, 0] = fx[(i - L1) * 3 + 2, 0]; } exSol = shift.Multiply(exSol) as SparseDoubleArray; foreach (var branch in _listBranch) { branch.shellCrv = branch.crv.Duplicate() as NurbsCurve; for (int i = 0; i < branch.N; i++) { var P = branch.shellCrv.Points[i].Location; branch.shellCrv.Points.SetPoint(i, new Point3d(exSol[branch.globalIndex[i] * 3 + 0, 0], exSol[branch.globalIndex[i] * 3 + 1, 0], exSol[branch.globalIndex[i] * 3 + 2, 0])); //if you don't want to allow movements of x and y coordinates, use the following instead of the above. //branch.shellCrv.Points.SetPoint(i, new Point3d(P.X, P.Y, exSol[branch.globalIndex[i] * 3 + 2, 0])); } } foreach (var leaf in _listLeaf) { leaf.shellSrf = leaf.srf.Duplicate() as NurbsSurface; for (int i = 0; i < leaf.nU; i++) { for (int j = 0; j < leaf.nV; j++) { var P = leaf.shellSrf.Points.GetControlPoint(i, j).Location; leaf.shellSrf.Points.SetControlPoint(i, j, new ControlPoint(exSol[leaf.globalIndex[i + j * leaf.nU] * 3 + 0, 0], exSol[leaf.globalIndex[i + j * leaf.nU] * 3 + 1, 0], exSol[leaf.globalIndex[i + j * leaf.nU] * 3 + 2, 0])); //if you don't want to allow movements of x and y coordinates, use the following instead of the above. //leaf.shellSrf.Points.SetControlPoint(i, j, new ControlPoint(P.X, P.Y, exSol[leaf.globalIndex[i + j * leaf.nU] * 3 + 2, 0])); } } } }
public void Solve(double[] input, double[] result) { lu.Solve(input, result); }
/// <summary> /// See <see cref="ITriangulation.SolveLinearSystem(Vector, Vector)"/>. /// </summary> public void SolveLinearSystem(Vectors.Vector rhs, Vectors.Vector solution) => factorization.Solve(rhs.RawData, solution.RawData);
public void Solve(Complex[] input, Complex[] result) { lu.Solve(input, result); }