2 changed files with 0 additions and 285 deletions
@ -1,284 +0,0 @@ |
|||
using BenchmarkDotNet.Attributes; |
|||
using BenchmarkDotNet.Configs; |
|||
using BenchmarkDotNet.Environments; |
|||
using BenchmarkDotNet.Jobs; |
|||
using MathNet.Numerics; |
|||
using MathNet.Numerics.LinearAlgebra; |
|||
using MathNet.Numerics.LinearAlgebra.Storage; |
|||
using MathNet.Numerics.Providers.Common.Mkl; |
|||
using MathNet.Numerics.Providers.SparseSolver; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Benchmark.SparseSolver |
|||
{ |
|||
[Config(typeof(Config))] |
|||
public class DirectSparseSolver |
|||
{ |
|||
class Config : ManualConfig |
|||
{ |
|||
public Config() |
|||
{ |
|||
AddJob(Job.Default.WithRuntime(ClrRuntime.Net461).WithPlatform(Platform.X64).WithJit(Jit.RyuJit)); |
|||
AddJob(Job.Default.WithRuntime(ClrRuntime.Net461).WithPlatform(Platform.X86).WithJit(Jit.LegacyJit)); |
|||
#if !NET461
|
|||
AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithPlatform(Platform.X64).WithJit(Jit.RyuJit)); |
|||
#endif
|
|||
} |
|||
} |
|||
|
|||
public enum ProviderId |
|||
{ |
|||
NativeMKL, |
|||
} |
|||
|
|||
[Params(32, 128, 1024)] |
|||
public int N { get; set; } |
|||
|
|||
[Params(ProviderId.NativeMKL)] |
|||
public ProviderId Provider { get; set; } |
|||
|
|||
int rowCount; |
|||
int columnCount; |
|||
int valueCount; |
|||
double[] values; |
|||
int[] rowPointers; |
|||
int[] columnIndices; |
|||
double[] rhs; |
|||
|
|||
[GlobalSetup] |
|||
public void GlobalSetup() |
|||
{ |
|||
switch (Provider) |
|||
{ |
|||
case ProviderId.NativeMKL: |
|||
Control.UseNativeMKL(MklConsistency.Auto, MklPrecision.Double, MklAccuracy.High); |
|||
break; |
|||
} |
|||
|
|||
var domain = new Domain(N); |
|||
domain.DefineProblem(); |
|||
|
|||
// Kmatrix is symmetric so, we need only upper triangle entries.
|
|||
var storage = domain.Kmatrix.UpperTriangle().Storage as SparseCompressedRowMatrixStorage<double>; |
|||
rowCount = storage.RowCount; |
|||
columnCount = storage.ColumnCount; |
|||
valueCount = storage.ValueCount; |
|||
values = storage.Values; |
|||
rowPointers = storage.RowPointers; |
|||
columnIndices = storage.ColumnIndices; |
|||
|
|||
rhs = domain.Rhs.ToArray(); |
|||
} |
|||
|
|||
[Benchmark(OperationsPerInvoke = 1)] |
|||
public double[] SolveProblem() |
|||
{ |
|||
double[] solution = new double[rowCount]; |
|||
SparseSolverControl.Provider.Solve(DssMatrixStructure.Symmetric, DssMatrixType.Indefinite, DssSystemType.NonTransposed, |
|||
rowCount, columnCount, valueCount, rowPointers, columnIndices, values, |
|||
1, rhs, solution); |
|||
return solution; |
|||
} |
|||
|
|||
#region Finite element method to solve Poisson's equation
|
|||
|
|||
class Node |
|||
{ |
|||
public int ID; |
|||
public double X; |
|||
|
|||
public Node(int id, double x) |
|||
{ |
|||
ID = id; |
|||
X = x; |
|||
} |
|||
} |
|||
|
|||
class Element |
|||
{ |
|||
public int ID; |
|||
public Node[] Nodes; |
|||
public double Alpha; |
|||
public double Gamma; |
|||
public Matrix<double> Kmatrix; |
|||
public Vector<double> Rhs; |
|||
|
|||
public Element(int id, Node node1, Node node2, double alpha, double gamma) |
|||
{ |
|||
ID = id; |
|||
Nodes = new[] { node1, node2 }; |
|||
Alpha = alpha; |
|||
Gamma = gamma; |
|||
} |
|||
|
|||
public void ComputeMatrices() |
|||
{ |
|||
var length = Nodes[1].X - Nodes[0].X; // length
|
|||
|
|||
Kmatrix = Matrix<double>.Build.Dense(2, 2); |
|||
Kmatrix[0, 0] = Alpha / length; |
|||
Kmatrix[0, 1] = -Alpha / length; |
|||
Kmatrix[1, 0] = -Alpha / length; |
|||
Kmatrix[1, 1] = Alpha / length; |
|||
|
|||
Rhs = Vector<double>.Build.Dense(2); |
|||
Rhs[0] = -Gamma * length / 2.0; |
|||
Rhs[1] = -Gamma * length / 2.0; |
|||
} |
|||
} |
|||
|
|||
class Domain |
|||
{ |
|||
// Length of the domain in [m]
|
|||
public double Length; |
|||
|
|||
// Dielectric constant of the domain
|
|||
public double Permittivity; |
|||
|
|||
// Charge density in [C/m^3]
|
|||
public double ChargeDensity; |
|||
|
|||
public double VoltageAtLeft; |
|||
public double VoltageAtRight; |
|||
|
|||
Node[] nodes; |
|||
Element[] elements; |
|||
List<Tuple<Node, double>> boundaries; |
|||
|
|||
public Matrix<double> Kmatrix; |
|||
public Vector<double> Rhs; |
|||
|
|||
public Domain(int elementCount = 4, double length = 0.08, double relativePermittivity = 1, double chargeDensity = 1E-8) |
|||
{ |
|||
// Boundary value problem:
|
|||
//
|
|||
// [0] ------ [1] ------ ... ------ [N]
|
|||
//
|
|||
// each element is characterized by an electron charge density and a dielectric constant
|
|||
//
|
|||
// V at node1 = 1V
|
|||
// V at node5 = 0V (ground)
|
|||
|
|||
Length = length; |
|||
|
|||
Permittivity = Constants.ElectricPermittivity * relativePermittivity; |
|||
ChargeDensity = chargeDensity; |
|||
|
|||
// Create nodes and elements
|
|||
nodes = new Node[elementCount + 1]; |
|||
elements = new Element[elementCount]; |
|||
|
|||
var dx = Length / elements.Length; |
|||
for (int i = 0; i < nodes.Length; i++) |
|||
{ |
|||
nodes[i] = new Node(i, dx * i); |
|||
} |
|||
for (int i = 0; i < elements.Length; i++) |
|||
{ |
|||
elements[i] = new Element(i, nodes[i], nodes[i + 1], Permittivity, ChargeDensity); |
|||
} |
|||
|
|||
// Initialization of the global K matrix and right-hand side vector
|
|||
Kmatrix = Matrix<double>.Build.Sparse(nodes.Length, nodes.Length); |
|||
Rhs = Vector<double>.Build.Dense(nodes.Length); |
|||
} |
|||
|
|||
public void DefineProblem(double Va = 1.0, double Vb = 0.0) |
|||
{ |
|||
VoltageAtLeft = Va; // Boundary condition at the leftmost node
|
|||
VoltageAtRight = Vb; // Boundary condition at the rightmost node
|
|||
|
|||
// Apply Dirichlet boundary conditions
|
|||
boundaries = new List<Tuple<Node, double>>(); |
|||
foreach (var node in nodes) |
|||
{ |
|||
if (node.X == 0) |
|||
{ |
|||
boundaries.Add(new Tuple<Node, double>(node, VoltageAtLeft)); |
|||
} |
|||
else if (node.X == Length) |
|||
{ |
|||
boundaries.Add(new Tuple<Node, double>(node, VoltageAtRight)); |
|||
} |
|||
} |
|||
|
|||
// Form the element matrices and assemble to the global matrix
|
|||
foreach (var element in elements) |
|||
{ |
|||
element.ComputeMatrices(); |
|||
|
|||
// Assemble element matrix into the global K matrix
|
|||
for (int i = 0; i < element.Nodes.Length; i++) |
|||
{ |
|||
var row = element.Nodes[i].ID; |
|||
for (int j = 0; j < element.Nodes.Length; j++) |
|||
{ |
|||
var col = element.Nodes[j].ID; |
|||
Kmatrix[row, col] += element.Kmatrix[i, j]; |
|||
} |
|||
Rhs[row] += element.Rhs[i]; |
|||
} |
|||
} |
|||
|
|||
// Imposition of Dirichlet boundary conditions
|
|||
foreach (var boundary in boundaries) |
|||
{ |
|||
var node = boundary.Item1; |
|||
var i = node.ID; |
|||
var val = boundary.Item2; |
|||
|
|||
for (int j = 0; j < nodes.Length; j++) |
|||
{ |
|||
if (nodes[j].ID != i) |
|||
Rhs[j] = Rhs[j] - Kmatrix[j, i] * val; |
|||
} |
|||
|
|||
Kmatrix.SetColumn(i, new double[Kmatrix.RowCount]); |
|||
Kmatrix.SetRow(i, new double[Kmatrix.ColumnCount]); |
|||
Kmatrix[i, i] = 1.0; |
|||
Rhs[i] = val; |
|||
} |
|||
} |
|||
|
|||
public double[] SolveProblem() |
|||
{ |
|||
// Kmatrix is symmetric so, we need only upper triangle entries.
|
|||
var storage = Kmatrix.UpperTriangle().Storage as SparseCompressedRowMatrixStorage<double>; |
|||
var rowCount = storage.RowCount; |
|||
var columnCount = storage.ColumnCount; |
|||
var valueCount = storage.ValueCount; |
|||
var values = storage.Values; |
|||
var rowPointers = storage.RowPointers; |
|||
var columnIndices = storage.ColumnIndices; |
|||
|
|||
var rhs = Rhs.ToArray(); |
|||
var solution = new double[rowCount]; |
|||
|
|||
SparseSolverControl.Provider.Solve(DssMatrixStructure.Symmetric, DssMatrixType.Indefinite, DssSystemType.NonTransposed, |
|||
rowCount, columnCount, valueCount, rowPointers, columnIndices, values, |
|||
1, rhs, solution); |
|||
|
|||
return solution; |
|||
} |
|||
|
|||
public double[] GetExactSolution() |
|||
{ |
|||
// Poisson's equation : ∇(ε∇V) = ρ
|
|||
// solution : V(x) = ρ/ε/2*x^2 - (ρ/ε/2*d + (Va - Vb)/d)*x + Va, where d = length
|
|||
|
|||
double[] Vexact = new double[nodes.Length]; |
|||
var factor = ChargeDensity / Permittivity * 0.5; |
|||
for (int i = 0; i < nodes.Length; i++) |
|||
{ |
|||
var x = nodes[i].X; |
|||
Vexact[i] = factor * x * x - factor * Length * x - (VoltageAtLeft - VoltageAtRight) / Length * x + VoltageAtLeft; |
|||
} |
|||
|
|||
return Vexact; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
Loading…
Reference in new issue