/// <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 double[] Muly(CompressedColumnStorage mtx, double[] vec) { var buf = new double[mtx.RowCount]; mtx.Multiply(vec, buf); return(buf); }
public static double ComputeResidual(CompressedColumnStorage <Complex> A, Complex[] x, Complex[] b, bool relativeError = true) { var e = Vector.Clone(b); A.Multiply(-1.0, x, 1.0, e); if (relativeError) { return(Vector.Norm(e) / (A.FrobeniusNorm() * Vector.Norm(b))); } return(Vector.Norm(e)); }
/// <summary> /// Gets the residual of Ax-b. /// </summary> /// <param name="A">A.</param> /// <param name="x">The x.</param> /// <param name="b">The b.</param> /// <returns></returns> public static double GetResidual(CompressedColumnStorage A, double[] x, double[] b) { var buf = 0.0; var n = b.Length; var recoveredB = new double[n]; A.Multiply(x, recoveredB); for (var i = 0; i < n; i++) { recoveredB[i] -= b[i]; } //var norm = recoveredB.GetLargestAbsoluteValue(); return (recoveredB.Average()); //Norm(recoveredB) / (A.Norm(MatrixNorm.OneNorm) * Norm(x) + Norm(b)); return(buf); }
protected override void Solve() { InitNeuronCell(); //if (SomaOn) { U.SetSubVector(0, myCell.vertCount, setSoma(U, myCell.somaID, vstart)); } int nT; // Number of Time steps List <bool> channels = new List <bool> { false, false, false }; // For adding/removing channels // TODO: NEED TO DO THIS BETTER if (HK_auto) { h = 0.1 * NeuronCell.edgeLengths.Average(); //if (h > 0.29) { h = 0.29; } if (h <= 1) { k = h / 140; } if (h <= 0.5) { k = h / 70; } if (h <= 0.25) { k = h / 35; } if (h <= 0.12) { k = h / 18; } if (h <= 0.06) { k = h / 9; } if (h <= 0.03) { k = h / 5; } } // Number of time steps nT = (int)System.Math.Floor(endTime / k); // set some constants for the HINES matrix double diffConst = (1 / (2 * res * cap)); double cfl = diffConst * k / h; // reaction vector Vector R = Vector.Build.Dense(NeuronCell.vertCount); List <double> reactConst = new List <double> { gk, gna, gl, ek, ena, el }; // temporary voltage vector Vector tempV = Vector.Build.Dense(NeuronCell.vertCount); // Construct sparse RHS and LHS in coordinate storage format, no zeros are stored List <CoordinateStorage <double> > sparse_stencils = makeSparseStencils(NeuronCell, h, k, diffConst); // Compress the sparse matrices CompressedColumnStorage <double> r_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[0]); //null; CompressedColumnStorage <double> l_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[1]); //null; // Permutation matrix----------------------------------------------------------------------// int[] p = new int[NeuronCell.vertCount]; p = Permutation.Create(NeuronCell.vertCount, 0); CompressedColumnStorage <double> Id_csc = CompressedColumnStorage <double> .CreateDiagonal(NeuronCell.vertCount, 1); Id_csc.PermuteRows(p); //--------------------------------------------------------------------------------------------// // for solving Ax = b problem double[] b = new double[NeuronCell.vertCount]; // Apply column ordering to A to reduce fill-in. //var order = ColumnOrdering.MinimumDegreeAtPlusA; // Create Cholesky factorization setup var chl = SparseCholesky.Create(l_csc, p); //var chl = SparseCholesky.Create(l_csc, order); try { for (i = 0; i < nT; i++) { if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } mutex.WaitOne(); r_csc.Multiply(U.ToArray(), b); // Peform b = rhs * U_curr // Diffusion solver chl.Solve(b, b); // Set U_next = b U.SetSubVector(0, NeuronCell.vertCount, Vector.Build.DenseOfArray(b)); // Save voltage from diffusion step for state probabilities tempV.SetSubVector(0, NeuronCell.vertCount, U); // Reaction channels[0] = na_ONOFF; channels[1] = k_ONOFF; channels[2] = leak_ONOFF; R.SetSubVector(0, NeuronCell.vertCount, reactF(reactConst, U, N, M, H, channels, NeuronCell.boundaryID)); R.Multiply(k / cap, R); // This is the solution for the voltage after the reaction is included! U.Add(R, U); //Now update state variables using FE on M,N,H N.Add(fN(tempV, N).Multiply(k), N); M.Add(fM(tempV, M).Multiply(k), M); H.Add(fH(tempV, H).Multiply(k), H); //Always reset to IC conditions and boundary conditions (for now) U.SetSubVector(0, NeuronCell.vertCount, boundaryConditions(U, NeuronCell.boundaryID)); if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } mutex.ReleaseMutex(); } } catch (Exception e) { GameManager.instance.DebugLogThreadSafe(e); } GameManager.instance.DebugLogSafe("Simulation Over."); }
protected override void Solve() { InitNeuronCell(); int nT; // Number of Time steps List <bool> channels = new List <bool>(); if (HK_auto) { h = 0.1 * NeuronCell.edgeLengths.Average(); if (h > 0.29) { h = 0.29; } if (h <= 1) { k = h / 100; } // For cell 13_0ref if (h <= 0.15) { k = h / 50; } // For cell 13_1ref if (h <= 0.08) { k = h / 25; } // For cell 13_2ref if (h <= 0.04) { k = h / 12.5; } // For cell 13_3ref if (h <= 0.02) { k = h / 5.5; } // For cell 13_4ref } if (use_Ck) { k = Ck * h; } // for timing data DateTime start; DateTime end; DateTime now = DateTime.Now; TimeSpan tspan; // setup up paths for writing output string strPath = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory); string subPath = strPath + @"\VR_Simulations"; bool exists = System.IO.Directory.Exists(subPath); // check if directory exists if (!exists) { System.IO.Directory.CreateDirectory(subPath); } // set the path for writing strPath = subPath; DirectoryInfo di = Directory.CreateDirectory(strPath + @"\SimulationRun" + "_" + now.Hour + "_" + now.Minute + "_" + now.Second); strPath = strPath + @"\SimulationRun" + "_" + now.Hour + "_" + now.Minute + "_" + now.Second; // Number of time steps nT = (int)System.Math.Floor(endTime / k); Timer timer = new Timer(nT + 1); timer.StartTimer(); // set some constants for the HINES matrix double diffConst = (1 / (2 * res * cap)); double cfl = diffConst * k / h; // pre-allocate 2d arrays, not jagged, maybe incorporate jagged arrays later? double[,] rhsMarray = new double[NeuronCell.vertCount, NeuronCell.vertCount]; double[,] lhsMarray = new double[NeuronCell.vertCount, NeuronCell.vertCount]; // reaction vector Vector R = Vector.Build.Dense(NeuronCell.vertCount); List <double> reactConst = new List <double> { gk, gna, gl, ek, ena, el }; // temporary voltage vector Vector tempV = Vector.Build.Dense(NeuronCell.vertCount); // Make the system stencil matrices for diffusion solve List <double[, ]> stencils = makeStencils(NeuronCell, h, k, diffConst); rhsMarray = stencils[0]; lhsMarray = stencils[1]; // Write rhsM and lhsM to file if (printMatrices) { printMatrix(rhsMarray, lhsMarray, strPath, now); } // for allocation of the sparse matrices CompressedColumnStorage <double> r_csc = null; CompressedColumnStorage <double> l_csc = null; // makes the rhs, lhs in sparse format r_csc = Converter.ToCompressedColumnStorage(Converter.FromDenseArray(rhsMarray)); l_csc = Converter.ToCompressedColumnStorage(Converter.FromDenseArray(lhsMarray)); // for solving Ax = b problem double[] b = new double[NeuronCell.vertCount]; // Apply column ordering to A to reduce fill-in. var order = ColumnOrdering.MinimumDegreeAtPlusA; // Create Cholesky factorization start = DateTime.Now; var chl = SparseCholesky.Create(l_csc, order); end = DateTime.Now; // Print cell info to a text file if (printCellInfo) { printCell(NeuronCell, h, k, nT, endTime, cfl, strPath, now, start, end); } // Write diffusion times to a file var timeWrite = new StreamWriter(strPath + @"\diffusion_times_chl_" + now.Hour + "_" + now.Minute + "_" + now.Second + ".txt", true); var sw = new StreamWriter(strPath + @"\outputVoltage_" + now.Hour + "_" + now.Minute + "_" + now.Second + ".txt", true); var tw = new StreamWriter(strPath + @"\timesteps_" + now.Hour + "_" + now.Minute + "_" + now.Second + ".txt", true); try { for (i = 0; i < nT; i++) { if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } timer.StartTimer(); mutex.WaitOne(); start = DateTime.Now; r_csc.Multiply(U.ToArray(), b); // Peform b = rhs * U_curr chl.Solve(b, b); b = maxCheck(b); end = DateTime.Now; tspan = end - start; // get time span to write timeWrite.WriteLine(tspan.TotalMilliseconds + Environment.NewLine); // write diffusion time to file // Set U_next = b U.SetSubVector(0, NeuronCell.vertCount, Vector.Build.DenseOfArray(b)); // Save voltage from diffusion step for state probabilities tempV.SetSubVector(0, NeuronCell.vertCount, U); // Reaction channels.Add(k_ONOFF); channels.Add(na_ONOFF); channels.Add(leak_ONOFF); R.SetSubVector(0, NeuronCell.vertCount, reactF(reactConst, U, N, M, H, channels, NeuronCell.boundaryID)); R.Multiply(k / cap, R); // This is the solution for the voltage after the reaction is included! U.Add(R, U); //Now update state variables using FE on M,N,H N.Add(fN(tempV, N).Multiply(k), N); M.Add(fM(tempV, M).Multiply(k), M); H.Add(fH(tempV, H).Multiply(k), H); //Always reset to IC conditions and boundary conditions (for now) U.SetSubVector(0, NeuronCell.vertCount, boundaryConditions(U, NeuronCell.boundaryID)); if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } if (printVolt_time) { for (int j = 0; j < NeuronCell.vertCount; j++) { sw.Write(U[j] + " "); } sw.Write("\n"); tw.Write((k * (double)i) + " "); tw.Write("\n"); } mutex.ReleaseMutex(); timer.StopTimer(i.ToString()); } timeWrite.Close(); sw.Close(); tw.Close(); } catch (Exception e) { GameManager.instance.DebugLogThreadSafe(e); } GameManager.instance.DebugLogSafe("Simulation Over."); }
protected override void Solve() { InitializeNeuronCell(); for (int kSim = 0; kSim <= numRuns; kSim++) { int nT; // Number of Time steps List <bool> channels = new List <bool> { false, false, false }; // For adding/removing channels // TODO: NEED TO DO THIS BETTER if (HK_auto) { h = 0.1 * NeuronCell.edgeLengths.Average(); if (h > 0.29) { h = 0.29; } if (h <= 1) { k = h / 100; } // For cell 13_0ref if (h <= 0.15) { k = h / 50; } // For cell 13_1ref if (h <= 0.08) { k = h / 25; } // For cell 13_2ref if (h <= 0.04) { k = h / 12.5; } // For cell 13_3ref if (h <= 0.02) { k = h / 5.5; } // For cell 13_4ref } // for timing data DateTime now = DateTime.Now; // setup up paths for writing output string strPath = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory); string subPath = strPath + @"\VR_Simulations"; bool exists = System.IO.Directory.Exists(subPath); // check if directory exists if (!exists) { System.IO.Directory.CreateDirectory(subPath); } // set the path for writing strPath = subPath; DirectoryInfo di = Directory.CreateDirectory(strPath + @"\SimulationRun" + "_" + kSim); strPath = strPath + @"\SimulationRun" + "_" + kSim; // Number of time steps nT = (int)System.Math.Floor(endTime / k); // set some constants for the HINES matrix double diffConst = (1 / (2 * res * cap)); double cfl = diffConst * k / h; //TODO: JAMES GET RID OF ARRAYS GO STRAIGHT FOR SPARSE ALLOCATION, THIS IS SILLY! --> QUEISSER/SEIBOLD! // pre-allocate 2d arrays, not jagged, maybe incorporate jagged arrays later? --> NO! double[,] rhsMarray = new double[NeuronCell.vertCount, NeuronCell.vertCount]; double[,] lhsMarray = new double[NeuronCell.vertCount, NeuronCell.vertCount]; // reaction vector Vector R = Vector.Build.Dense(NeuronCell.vertCount); List <double> reactConst = new List <double> { gk, gna, gl, ek, ena, el }; // temporary voltage vector Vector tempV = Vector.Build.Dense(NeuronCell.vertCount); // TODO: turn make stencils function to use sparse allocation!! --> QUEISSER/SEIBOLD! // Make the system stencil matrices for diffusion solve List <double[, ]> stencils = makeStencils(NeuronCell, h, k, diffConst); rhsMarray = stencils[0]; lhsMarray = stencils[1]; // Write rhsM and lhsM to file if (printMatrices) { printMatrix(rhsMarray, lhsMarray, strPath, kSim); } // for allocation of the sparse matrices CompressedColumnStorage <double> r_csc = null; CompressedColumnStorage <double> l_csc = null; // makes the rhs, lhs in sparse format r_csc = Converter.ToCompressedColumnStorage(Converter.FromDenseArray(rhsMarray)); l_csc = Converter.ToCompressedColumnStorage(Converter.FromDenseArray(lhsMarray)); // for solving Ax = b problem double[] b = new double[NeuronCell.vertCount]; // TODO: UNDERSTAND WHAT THIS IS DOING! --> QUEISSER/SEIBOLD! // Apply column ordering to A to reduce fill-in. var order = ColumnOrdering.MinimumDegreeAtPlusA; // TODO: GO INTO Source code and print the L matrix // Time the reordering steps? --> Ask Queisser again about this! // Create Cholesky factorization setup Timer timer = new Timer(1); timer.StartTimer(); var chl = SparseCholesky.Create(l_csc, order); timer.StopTimer("MatSetup t= "); timer.ExportCSV("matrixSetup"); // Print cell info to a text file if (printCellInfo) { printCell(NeuronCell, h, k, nT, endTime, cfl, strPath, kSim); } // For printing voltage data and time steps var sw = new StreamWriter(strPath + @"\outputVoltage_" + kSim + ".txt", true); var tw = new StreamWriter(strPath + @"\timesteps_" + kSim + ".txt", true); timer = new Timer(nT); try { for (i = 0; i < nT; i++) { if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } mutex.WaitOne(); r_csc.Multiply(U.ToArray(), b); // Peform b = rhs * U_curr // Diffusion solver timer.StartTimer(); chl.Solve(b, b); timer.StopTimer(i.ToString()); // Set U_next = b U.SetSubVector(0, NeuronCell.vertCount, Vector.Build.DenseOfArray(b)); // Save voltage from diffusion step for state probabilities tempV.SetSubVector(0, NeuronCell.vertCount, U); // Reaction channels[0] = na_ONOFF; channels[1] = k_ONOFF; channels[2] = leak_ONOFF; R.SetSubVector(0, NeuronCell.vertCount, reactF(reactConst, U, N, M, H, channels, NeuronCell.boundaryID)); R.Multiply(k / cap, R); // This is the solution for the voltage after the reaction is included! U.Add(R, U); //Now update state variables using FE on M,N,H N.Add(fN(tempV, N).Multiply(k), N); M.Add(fM(tempV, M).Multiply(k), M); H.Add(fH(tempV, H).Multiply(k), H); //Always reset to IC conditions and boundary conditions (for now) U.SetSubVector(0, NeuronCell.vertCount, boundaryConditions(U, NeuronCell.boundaryID)); if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } if (printVolt_time) { for (int j = 0; j < NeuronCell.vertCount; j++) { sw.Write(U[j] + " "); } sw.Write("\n"); tw.Write((k * (double)i) + " "); tw.Write("\n"); } mutex.ReleaseMutex(); } sw.Close(); tw.Close(); } catch (Exception e) { GameManager.instance.DebugLogThreadSafe(e); } finally { timer.ExportCSV("diffusionTimes"); sw.Close(); tw.Close(); } GameManager.instance.DebugLogSafe("Simulation Over."); } }
protected override void Solve() { InitNeuronCell(); for (int kSim = 0; kSim <= numRuns; kSim++) { //if (SomaOn) { U.SetSubVector(0, myCell.vertCount, setSoma(U, myCell.somaID, vstart)); } int nT; // Number of Time steps List <bool> channels = new List <bool> { false, false, false }; // For adding/removing channels // TODO: NEED TO DO THIS BETTER if (HK_auto) { h = 0.1 * NeuronCell.edgeLengths.Average(); //if (h > 0.29) { h = 0.29; } if (h <= 1) { k = h / 130; } // 0 refine if (h <= 0.5) { k = h / 65; } // 1 refine if (h <= 0.25) { k = h / 32.5; } // 2 refine if (h <= 0.12) { k = h / 18; } // 3 refine if (h <= 0.06) { k = h / 9; } // 4 refine if (h <= 0.03) { k = h / 5; } } // setup up paths for writing output string strPath = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory); string subPath = strPath + @"\VR_Simulations"; bool exists = System.IO.Directory.Exists(subPath); // check if directory exists if (!exists) { System.IO.Directory.CreateDirectory(subPath); } // set the path for writing strPath = subPath; DirectoryInfo di = Directory.CreateDirectory(strPath + @"\SimulationRun" + "_" + kSim); strPath = strPath + @"\SimulationRun" + "_" + kSim; // Number of time steps nT = (int)System.Math.Floor(endTime / k); // set some constants for the HINES matrix double diffConst = (1 / (2 * res * cap)); double cfl = diffConst * k / h; // reaction vector Vector R = Vector.Build.Dense(NeuronCell.vertCount); List <double> reactConst = new List <double> { gk, gna, gl, ek, ena, el }; // temporary voltage vector Vector tempV = Vector.Build.Dense(NeuronCell.vertCount); // Construct sparse RHS and LHS in coordinate storage format, no zeros are stored List <CoordinateStorage <double> > sparse_stencils = makeSparseStencils(NeuronCell, h, k, diffConst); // Compress the sparse matrices CompressedColumnStorage <double> r_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[0]); //null; CompressedColumnStorage <double> l_csc = CompressedColumnStorage <double> .OfIndexed(sparse_stencils[1]); //null; // Permutation matrix----------------------------------------------------------------------// int[] p = new int[NeuronCell.vertCount]; if (randomPermute) { p = Permutation.Create(NeuronCell.vertCount, 1); } else { p = Permutation.Create(NeuronCell.vertCount, 0); } CompressedColumnStorage <double> Id_csc = CompressedColumnStorage <double> .CreateDiagonal(NeuronCell.vertCount, 1); Id_csc.PermuteRows(p); //--------------------------------------------------------------------------------------------// // for solving Ax = b problem double[] b = new double[NeuronCell.vertCount]; // Apply column ordering to A to reduce fill-in. //var order = ColumnOrdering.MinimumDegreeAtPlusA; // Create Cholesky factorization setup Timer timer = new Timer(); timer.StartTimer(); var chl = SparseCholesky.Create(l_csc, p); //var chl = SparseCholesky.Create(l_csc, order); timer.StopTimer("Matrix Setup"); timer.ExportCSV_path(strPath + @"\chlSetup_" + kSim); // Write permutation, rhsM, lhsM, and choleskyR matrix to file if (printMatrices) { printMatrix(Id_csc, r_csc, l_csc, chl.L, strPath, kSim); } // Print cell info to a text file if (printCellInfo) { printCell(NeuronCell, h, k, nT, endTime, cfl, strPath, kSim); } // For printing voltage data and time steps var sw = new StreamWriter(strPath + @"\outputVoltage_" + kSim + ".txt", true); var tw = new StreamWriter(strPath + @"\timesteps_" + kSim + ".txt", true); timer = new Timer(nT); try { for (i = 0; i < nT; i++) { if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } mutex.WaitOne(); r_csc.Multiply(U.ToArray(), b); // Peform b = rhs * U_curr // Diffusion solver timer.StartTimer(); chl.Solve(b, b); timer.StopTimer(i.ToString()); // Set U_next = b U.SetSubVector(0, NeuronCell.vertCount, Vector.Build.DenseOfArray(b)); // Save voltage from diffusion step for state probabilities tempV.SetSubVector(0, NeuronCell.vertCount, U); // Reaction channels[0] = na_ONOFF; channels[1] = k_ONOFF; channels[2] = leak_ONOFF; R.SetSubVector(0, NeuronCell.vertCount, reactF(reactConst, U, N, M, H, channels, NeuronCell.boundaryID)); R.Multiply(k / cap, R); // This is the solution for the voltage after the reaction is included! U.Add(R, U); //Now update state variables using FE on M,N,H N.Add(fN(tempV, N).Multiply(k), N); M.Add(fM(tempV, M).Multiply(k), M); H.Add(fH(tempV, H).Multiply(k), H); //Always reset to IC conditions and boundary conditions (for now) U.SetSubVector(0, NeuronCell.vertCount, boundaryConditions(U, NeuronCell.boundaryID)); if (SomaOn) { U.SetSubVector(0, NeuronCell.vertCount, setSoma(U, NeuronCell.somaID, vstart)); } if (printVolt_time) { for (int j = 0; j < NeuronCell.vertCount; j++) { sw.Write(U[j] + " "); } sw.Write("\n"); tw.Write((k * (double)i) + " "); tw.Write("\n"); } mutex.ReleaseMutex(); } sw.Close(); tw.Close(); } catch (Exception e) { GameManager.instance.DebugLogThreadSafe(e); } finally { timer.ExportCSV_path(strPath + @"\diffusionTimes_" + kSim); sw.Close(); tw.Close(); } GameManager.instance.DebugLogSafe("Simulation Over."); } }