CPP-snippets 0.0.1
A silly C++ project to use for demonstrating code integration
Loading...
Searching...
No Matches
simulation.cpp
1#include <cmath>
2#include <iostream>
3
4#include <ostream>
5#include <random>
6#include <toml++/toml.hpp>
7#include <Eigen/SparseCholesky>
8
9#include "simulation.hpp"
10#include "Eigen/Core"
11#include "constants.hpp"
12#include "interface.hpp"
13#include "particles.hpp"
14#include "poisson.hpp"
15
16
17Simulation::Simulation(const IOInterface *interface) : m_interface(interface) {
18
19 std::cout << " -> Initializing simulation ..." << std::endl;
20
21 // reproducable "random" numbers
22 m_rng.seed(12345);
23
24 // Init Poisson field solver
25 Eigen::Vector4d pos = m_interface->load_vector<Eigen::Vector4d>("geometry.positions");
26 Eigen::Vector4d pots = m_interface->load_vector<Eigen::Vector4d>("geometry.potentials");
27 Eigen::Vector3i cells = m_interface->load_vector<Eigen::Vector3i>("discretization.space.cells");
28 m_poisson = new PoissonSolver(pos, pots, cells);
29
30 // Init particle storage
31 double sp_weight = m_interface->load_scalar<double>("solve.particles.weight");
32 m_particles = new Particles(0, constants::q_e, constants::m_e, sp_weight);
33
34 // Init solution storage
35 double t_final = m_interface->load_scalar<double>("discretization.time.t_final");
36 double dt = m_interface->load_scalar<double>("discretization.time.dt");
37 m_cellnumber = cells.sum();
38 m_timesteps = static_cast<int>(std::ceil(t_final / dt));
39
40 m_time = Eigen::VectorXd::LinSpaced(m_timesteps, 0, m_timesteps * dt);
41 m_phi = Eigen::MatrixXd::Zero(m_timesteps, m_cellnumber+1);
42 m_rho = Eigen::MatrixXd::Zero(m_timesteps, m_cellnumber+1);
43 m_efield = Eigen::MatrixXd::Zero(m_timesteps, m_cellnumber+1);
44
45 // Init postproc storage
46 m_bins = m_interface->load_scalar<int>("discretization.energy.bins");
47 m_energy_dist = Eigen::MatrixXd::Zero(m_timesteps, m_bins);
48 m_fluxes = Eigen::MatrixX4d::Zero(m_timesteps, 4);
49
50};
51
53
54 std::cout << " -> Running the simulation ..." << std::endl;
55 // general
56
57 double source_flux_avg = m_interface->load_scalar<double>("solve.particles.source_flux");
58 double initial_energy = m_interface->load_scalar<double>("solve.particles.init_energy");
59 // collsions
60 double p_ce = m_interface->load_scalar<double>("solve.collisions.prob_ce");
61 double p_ag = m_interface->load_scalar<double>("solve.collisions.prob_ag");
62 // max histogram energy
63 double energy_max = m_interface->load_scalar<double>("discretization.energy.max");
64
65
66 // Electron source with poisson distribution
67 double dt = m_time[1] - m_time[0];
68 std::poisson_distribution<int> pois(source_flux_avg * dt / m_particles->m_weight);
69 double N_emit; // average number of electrons to emit over each timestep
70
71 // Initial laplace solution
72 std::cout << "[0] Solving initial Laplace " << std::endl;
73 Eigen::VectorXd rho = Eigen::VectorXd::Zero(m_cellnumber+1);
74 Eigen::VectorXd phi = m_poisson->solve_potential(rho);
75 Eigen::VectorXd efield = m_poisson->solve_efield(phi);
76 Eigen::VectorXd energies = Eigen::VectorXd::Zero(m_bins);
77 Eigen::Vector4d fluxes = Eigen::Vector4d::Zero(4);
78 m_phi.row(0) = phi.transpose();
79 m_efield.row(0) = efield.transpose();
80
81 // loop over rest of timestep here ...
82 for (int i = 1; i < m_timesteps; i++) {
83
84 std::cout << "["<< i << "] Solving timestep " << std::endl;
85
86 // Emit on x=0 with boltzmann distributed velocities and poisson dist particle count
87 N_emit = pois(m_rng);
88 m_particles->emit(
89 N_emit, 0, dt, initial_energy,
90 m_poisson->m_nodes, efield, m_rng
91 );
92 // Move particles in efield solution
93 m_particles->push_leapfrog(dt, m_poisson->m_nodes, efield);
94 // Check for absorbtion
95 fluxes = m_particles->fluxes(m_poisson->m_cap_xpos, m_rng, p_ce, p_ag);
96 energies = m_particles->energy_distribution(m_bins, energy_max);
97 // Deposite charge on grid
98 rho = m_particles->deposit_charge(m_poisson->m_nodes, m_poisson->m_dx);
99 // Update field solution w. Poisson solver
100 phi = m_poisson->solve_potential(rho);
101 efield = m_poisson->solve_efield(phi);
102
103 // Save step quantities
104 m_rho.row(i) = rho.transpose();
105 m_phi.row(i) = phi.transpose();
106 m_efield.row(i) = efield.transpose();
107 m_fluxes.row(i) = fluxes.transpose();
108 m_energy_dist.row(i) = energies.transpose();
109
110 }
111
112 std::cout << " Finished simulation run " << std::endl;
113};
114
115
117
118 std::cout << " -> Postprocessing results ..." << std::endl;
119
120 // export results
121 std::string comment = " | Time discretization";
122 m_interface->write2csv("time_vec.csv", m_time, comment);
123
124 comment = " | Cell sizes";
125 m_interface->write2csv("dx_vec.csv", m_poisson->m_dx, comment);
126 comment = " | Node positions";
127 m_interface->write2csv("nodes_vec.csv", m_poisson->m_nodes, comment);
128
129 comment = " | Charge density on nodes (rows: timesteps, cols: nodes)";
130 m_interface->write2csv("rho_mat.csv", m_rho, comment);
131 comment = " | Electric potential on nodes (rows: timesteps, cols: nodes)";
132 m_interface->write2csv("phi_mat.csv", m_phi, comment);
133 comment = " | Electric field in cells (rows: timesteps, cols: cells)";
134 m_interface->write2csv("efield_mat.csv", m_efield, comment);
135 comment = " | Electrode currents (rows: timesteps, cols: {1-Fil, 2-CE, 3-AG, 4-IC})";
136 m_interface->write2csv("currents_mat.csv", m_fluxes, comment);
137 comment = " | Electron kinetic energy distribution (rows: timesteps, cols: equidist. bins)";
138 m_interface->write2csv("energy_mat.csv", m_energy_dist, comment);
139
140};
Stores and advances a dynamically sized set of 1D superparticles.
Definition particles.hpp:13
void run()
Execute the complete PIC time integration loop.
Simulation(const IOInterface *interface)
Construct the simulation from an IO interface.
void postprocess()
Write simulation results to output files.