CPP-snippets 0.0.1
A silly C++ project to use for demonstrating code integration
Loading...
Searching...
No Matches
poisson.cpp
1#include <iostream>
2#include <Eigen/SparseCholesky>
3
4#include "poisson.hpp"
5#include "Eigen/Core"
6#include "constants.hpp"
7
8PoissonSolver::PoissonSolver(Eigen::Vector4d positions, Eigen::Vector4d potentials, Eigen::Vector3i cells) :
9 m_cap_xpos(positions), m_cap_pots(potentials), m_cap_cells(cells) {
10
11 // Discretizations (nodes and cell distances)
12 m_nodes.resize(m_cap_cells.sum() + 1);
13 m_nodes <<
14 Eigen::VectorXd::Constant(1, m_cap_xpos[0]),
15 Eigen::VectorXd::LinSpaced(m_cap_cells[0] + 1,m_cap_xpos[0],m_cap_xpos[1]).tail(m_cap_cells[0]),
16 Eigen::VectorXd::LinSpaced(m_cap_cells[1] + 1,m_cap_xpos[1],m_cap_xpos[2]).tail(m_cap_cells[1]),
17 Eigen::VectorXd::LinSpaced(m_cap_cells[2] + 1,m_cap_xpos[2],m_cap_xpos[3]).tail(m_cap_cells[2]);
18 m_dx.resize(m_nodes.size() - 1);
19 for (int i = 0; i < m_nodes.size() - 1; i++) {
20 m_dx(i) = m_nodes(i+1) - m_nodes(i);
21 }
22 std::cout << " Space discretization:" <<
23 m_dx[0] << " | " <<
24 m_dx[m_cap_cells[0]+1] << " | " <<
25 m_dx[m_cap_cells[0]+m_cap_cells[1]+1] << std::endl;
26
27 // build finite difference matrices for each capacitor
28 m_cap0_mat = this->tridiag(m_cap_cells[0] - 1);
29 m_cap1_mat = this->tridiag(m_cap_cells[1] - 1);
30 m_cap2_mat = this->tridiag(m_cap_cells[2] - 1);
31
32};
33
34Eigen::SparseMatrix<double> PoissonSolver::tridiag(int size){
35
36 // sparse system matrix for second derivative in space
37 typedef Eigen::Triplet<double> T;
38 std::vector<T> triplets;
39
40 for (int i = 0; i < size; ++i) {
41 triplets.emplace_back(i, i, 2); // main diagonal
42 if (i > 0) triplets.emplace_back(i, i - 1, -1); // subdiagonal
43 if (i < size-1) triplets.emplace_back(i, i + 1, -1); // superdiagonal
44 }
45
46 Eigen::SparseMatrix<double> A(size, size);
47 A.setFromTriplets(triplets.begin(), triplets.end());
48 return A;
49
50};
51
52
53Eigen::VectorXd PoissonSolver::solve_potential(Eigen::VectorXd& rho) {
54
55 std::cout << " + solving poisson potential " << std::endl;
56 double dx0 = m_dx[0];
57 double dx1 = m_dx[m_cap_cells[0]+1];
58 double dx2 = m_dx[m_cap_cells[0]+m_cap_cells[1]+1];
59
60 // initial stage of the system is equal to laplace equation
61 Eigen::VectorXd timestep_rhs0 =
62 rho.segment(1, m_cap_cells[0]-1) * std::pow(dx0,2) / constants::eps0;
63 Eigen::VectorXd timestep_rhs1 =
64 rho.segment(m_cap_cells[0]+2, m_cap_cells[1]-1) * std::pow(dx1, 2) / constants::eps0;
65 Eigen::VectorXd timestep_rhs2 =
66 rho.segment(m_cap_cells[0] + m_cap_cells[1] + 2, m_cap_cells[2]-1) * std::pow(dx2, 2) / constants::eps0;
67 timestep_rhs0(0) += m_cap_pots[0];
68 timestep_rhs0.tail(1)(0) += m_cap_pots[1];
69 timestep_rhs1(0) += m_cap_pots[1];
70 timestep_rhs1.tail(1)(0) += m_cap_pots[2];
71 timestep_rhs2(0) += m_cap_pots[2];
72 timestep_rhs2.tail(1)(0) += m_cap_pots[3];
73
74 // solve system(s)
75 Eigen::SimplicialLLT<Eigen::SparseMatrix<double>> solver;
76
77 solver.compute(m_cap0_mat);
78 Eigen::VectorXd phi0 = solver.solve(timestep_rhs0);
79 solver.compute(m_cap1_mat);
80 Eigen::VectorXd phi1 = solver.solve(timestep_rhs1);
81 solver.compute(m_cap2_mat);
82 Eigen::VectorXd phi2 = solver.solve(timestep_rhs2);
83 if(solver.info()!=Eigen::Success) {
84 std::cerr << "Solving failed!" << std::endl;
85 }
86
87 // Merge potential solutions and include electrodes
88 Eigen::VectorXd nodal_phi(m_nodes.size());
89 nodal_phi <<
90 Eigen::VectorXd::Constant(1, m_cap_pots[0]),
91 phi0,
92 Eigen::VectorXd::Constant(1, m_cap_pots[1]),
93 phi1,
94 Eigen::VectorXd::Constant(1, m_cap_pots[2]),
95 phi2,
96 Eigen::VectorXd::Constant(1, m_cap_pots[3]);
97
98 return nodal_phi;
99};
100
101Eigen::VectorXd PoissonSolver::solve_efield(Eigen::VectorXd& nodal_phi){
102
103 // 0th order e field calculation
104 int n_nodes = nodal_phi.size();
105 Eigen::VectorXd nodal_efield = Eigen::VectorXd::Zero(n_nodes);
106
107 double hL;
108 double hR;
109 // ---------------------------
110 // Central differences interior nodes
111 // ---------------------------
112 for (int i = 1; i < n_nodes-1; i++) {
113 hL = m_dx[i-1];
114 hR = m_dx[i];
115
116 nodal_efield[i] =
117 (hL*hL * (nodal_phi[i+1]-nodal_phi[i])
118 + hR*hR * (nodal_phi[i]-nodal_phi[i-1]))
119 / (hL*hR * (hL+hR));
120 }
121
122
123 // left boundary (i = 0):
124 {
125 double h1 = m_dx[0];
126 double h2 = m_dx[1];
127 nodal_efield[0] = -(
128 - (2*h1 + h2)/(h1*(h1 + h2)) * nodal_phi[0]
129 + (h1 + h2)/(h1*h2) * nodal_phi[1]
130 - h1/(h2*(h1 + h2)) * nodal_phi[2]
131 );
132 }
133 // right boundary (i = N-1):
134 {
135 double h1 = m_dx[n_nodes-2];
136 double h2 = m_dx[n_nodes-3];
137 nodal_efield[n_nodes-1] = -(
138 + (2*h1 + h2)/(h1*(h1 + h2)) * nodal_phi[n_nodes-1]
139 - (h1 + h2)/(h1*h2) * nodal_phi[n_nodes-2]
140 + h1/(h2*(h1 + h2)) * nodal_phi[n_nodes-3]
141 );
142 }
143
144 return nodal_efield;
145};