Develop #14
@ -74,8 +74,8 @@ public:
|
|||||||
* */
|
* */
|
||||||
PenningTrap(
|
PenningTrap(
|
||||||
double B_0 = T,
|
double B_0 = T,
|
||||||
std::function<double(double)> V_0 =
|
std::function<double(double)> V_0
|
||||||
[](double t) { return 25. * V / 1000.; },
|
= [](double t) { return 25. * V / 1000.; },
|
||||||
double d = 500., double t = 0.);
|
double d = 500., double t = 0.);
|
||||||
|
|
||||||
/** @brief Constructor for the PenningTrap class
|
/** @brief Constructor for the PenningTrap class
|
||||||
@ -88,8 +88,8 @@ public:
|
|||||||
* */
|
* */
|
||||||
PenningTrap(
|
PenningTrap(
|
||||||
unsigned int i, double B_0 = T,
|
unsigned int i, double B_0 = T,
|
||||||
std::function<double(double)> V_0 =
|
std::function<double(double)> V_0
|
||||||
[](double t) { return 25. * V / 1000.; },
|
= [](double t) { return 25. * V / 1000.; },
|
||||||
double d = 500., double t = 0.);
|
double d = 500., double t = 0.);
|
||||||
|
|
||||||
/** @brief Constructor for the PenningTrap class
|
/** @brief Constructor for the PenningTrap class
|
||||||
@ -102,10 +102,21 @@ public:
|
|||||||
* */
|
* */
|
||||||
PenningTrap(
|
PenningTrap(
|
||||||
std::vector<Particle> particles, double B_0 = T,
|
std::vector<Particle> particles, double B_0 = T,
|
||||||
std::function<double(double)> V_0 =
|
std::function<double(double)> V_0
|
||||||
[](double t) { return 25. * V / 1000.; },
|
= [](double t) { return 25. * V / 1000.; },
|
||||||
double d = 500., double t = 0.);
|
double d = 500., double t = 0.);
|
||||||
|
|
||||||
|
/** @brief Give all particles new positions and velocities, and change t
|
||||||
|
* and V_0.
|
||||||
|
*
|
||||||
|
* @param V_0 The tiome dependent applied potential
|
||||||
|
* @param t The starting time
|
||||||
|
* */
|
||||||
|
void reinitialize(
|
||||||
|
std::function<double(double)> V_0
|
||||||
|
= [](double t) { return 25. * V / 1000.; },
|
||||||
|
double t = 0.);
|
||||||
|
|
||||||
/** @brief Add a particle to the system
|
/** @brief Add a particle to the system
|
||||||
*
|
*
|
||||||
* @param particle The particle to add to the Penning trap
|
* @param particle The particle to add to the Penning trap
|
||||||
@ -151,7 +162,8 @@ public:
|
|||||||
* */
|
* */
|
||||||
vec_3d total_force_external(unsigned int i);
|
vec_3d total_force_external(unsigned int i);
|
||||||
|
|
||||||
/** @brief Calculate the total force on a particle p_i from other particles.
|
/** @brief Calculate the total force on a particle p_i from other
|
||||||
|
* particles.
|
||||||
*
|
*
|
||||||
* @param i The index of particle p_i
|
* @param i The index of particle p_i
|
||||||
*
|
*
|
||||||
@ -204,7 +216,8 @@ public:
|
|||||||
* @param particle_interaction Turn particle interactions on/off
|
* @param particle_interaction Turn particle interactions on/off
|
||||||
* */
|
* */
|
||||||
void write_simulation_to_dir(std::string path, double time,
|
void write_simulation_to_dir(std::string path, double time,
|
||||||
unsigned int steps, std::string method = "rk4",
|
unsigned int steps,
|
||||||
|
std::string method = "rk4",
|
||||||
bool particle_interaction = true);
|
bool particle_interaction = true);
|
||||||
|
|
||||||
/** @brief Simulate and calculate what fraction of particles are still
|
/** @brief Simulate and calculate what fraction of particles are still
|
||||||
|
|||||||
@ -11,7 +11,10 @@
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
#include "PenningTrap.hpp"
|
#include "PenningTrap.hpp"
|
||||||
|
#include "typedefs.hpp"
|
||||||
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
PenningTrap::PenningTrap(double B_0, std::function<double(double)> V_0,
|
PenningTrap::PenningTrap(double B_0, std::function<double(double)> V_0,
|
||||||
double d, double t)
|
double d, double t)
|
||||||
@ -26,11 +29,9 @@ PenningTrap::PenningTrap(unsigned int i, double B_0,
|
|||||||
std::function<double(double)> V_0, double d, double t)
|
std::function<double(double)> V_0, double d, double t)
|
||||||
: PenningTrap::PenningTrap(B_0, V_0, d)
|
: PenningTrap::PenningTrap(B_0, V_0, d)
|
||||||
{
|
{
|
||||||
vec_3d r, v;
|
|
||||||
for (size_t j = 0; j < i; j++) {
|
for (size_t j = 0; j < i; j++) {
|
||||||
r = vec_3d().randn() * .1 * this->d;
|
this->particles.push_back(Particle(1., 40., vec_3d(vec_3d().randn() * .1 * this->d),
|
||||||
v = vec_3d().randn() * .1 * this->d;
|
vec_3d(vec_3d().randn() * .1 * this->d)));
|
||||||
this->add_particle(Particle(1., 40., r, v));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +42,16 @@ PenningTrap::PenningTrap(std::vector<Particle> particles, double B_0,
|
|||||||
this->particles = particles;
|
this->particles = particles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PenningTrap::reinitialize(std::function<double(double)> V_0, double t)
|
||||||
|
{
|
||||||
|
this->V_0 = V_0;
|
||||||
|
this->t = t;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < this->particles.size(); i++) {
|
||||||
|
this->particles[i].r_vec = vec_3d().randn() * .1 * this->d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vec_3d PenningTrap::v_func(unsigned int i, unsigned int j, double dt)
|
vec_3d PenningTrap::v_func(unsigned int i, unsigned int j, double dt)
|
||||||
{
|
{
|
||||||
switch (i) {
|
switch (i) {
|
||||||
@ -109,15 +120,16 @@ vec_3d PenningTrap::force_on_particle(unsigned int i, unsigned int j)
|
|||||||
|
|
||||||
vec_3d PenningTrap::total_force_external(unsigned int i)
|
vec_3d PenningTrap::total_force_external(unsigned int i)
|
||||||
{
|
{
|
||||||
Particle p = this->particles[i];
|
Particle *p = &this->particles[i];
|
||||||
|
|
||||||
if (arma::norm(p.r_vec) > this->d) {
|
if (arma::norm(p->r_vec) > this->d) {
|
||||||
return vec_3d{0., 0., 0.};
|
return vec_3d{0., 0., 0.};
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec_3d(p.q
|
return vec_3d(
|
||||||
* (this->external_E_field(p.r_vec)
|
p->q
|
||||||
+ arma::cross(p.v_vec, this->external_B_field(p.r_vec))));
|
* (this->external_E_field(p->r_vec)
|
||||||
|
+ arma::cross(p->v_vec, this->external_B_field(p->r_vec))));
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_3d PenningTrap::total_force_particles(unsigned int i)
|
vec_3d PenningTrap::total_force_particles(unsigned int i)
|
||||||
@ -134,9 +146,10 @@ vec_3d PenningTrap::total_force_particles(unsigned int i)
|
|||||||
|
|
||||||
vec_3d PenningTrap::total_force(unsigned int i)
|
vec_3d PenningTrap::total_force(unsigned int i)
|
||||||
{
|
{
|
||||||
return arma::norm(this->particles[i].r_vec) > this->d
|
if (arma::norm(this->particles[i].r_vec) > this->d) {
|
||||||
? vec_3d{0., 0., 0.}
|
return vec_3d{0., 0., 0.};
|
||||||
: vec_3d(this->total_force_external(i)
|
}
|
||||||
|
return vec_3d(this->total_force_external(i)
|
||||||
- this->total_force_particles(i));
|
- this->total_force_particles(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,13 +159,9 @@ void PenningTrap::evolve_RK4(double dt, bool particle_interaction)
|
|||||||
std::vector<Particle> original_particles = this->particles;
|
std::vector<Particle> original_particles = this->particles;
|
||||||
std::vector<Particle> tmp_particles = this->particles;
|
std::vector<Particle> tmp_particles = this->particles;
|
||||||
|
|
||||||
vec_3d (PenningTrap::*force)(unsigned int);
|
vec_3d (PenningTrap::*force)(unsigned int)
|
||||||
if (particle_interaction) {
|
= particle_interaction ? &PenningTrap::total_force
|
||||||
force = &PenningTrap::total_force;
|
: &PenningTrap::total_force_external;
|
||||||
}
|
|
||||||
else {
|
|
||||||
force = &PenningTrap::total_force_external;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size = this->particles.size();
|
size_t size = this->particles.size();
|
||||||
|
|
||||||
@ -163,7 +172,9 @@ void PenningTrap::evolve_RK4(double dt, bool particle_interaction)
|
|||||||
this->k_r = sim_arr(4, sim_cols(size));
|
this->k_r = sim_arr(4, sim_cols(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Each k_{i+1} is dependent on k_i, so outer loop is not parallelizable
|
||||||
for (size_t i = 0; i < 4; i++) {
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
// Inner loop is able to be parallelized
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
for (size_t j = 0; j < size; j++) {
|
for (size_t j = 0; j < size; j++) {
|
||||||
this->k_v[i][j] = (this->*force)(j) / this->particles[j].m;
|
this->k_v[i][j] = (this->*force)(j) / this->particles[j].m;
|
||||||
@ -176,6 +187,7 @@ void PenningTrap::evolve_RK4(double dt, bool particle_interaction)
|
|||||||
}
|
}
|
||||||
this->particles = tmp_particles;
|
this->particles = tmp_particles;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->t += dt;
|
this->t += dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,19 +197,19 @@ void PenningTrap::evolve_forward_euler(double dt, bool particle_interaction)
|
|||||||
vec_3d force_res[size];
|
vec_3d force_res[size];
|
||||||
Particle *p;
|
Particle *p;
|
||||||
|
|
||||||
vec_3d (PenningTrap::*force)(unsigned int);
|
vec_3d (PenningTrap::*force)(unsigned int)
|
||||||
if (particle_interaction) {
|
= particle_interaction ? &PenningTrap::total_force
|
||||||
force = &PenningTrap::total_force_external;
|
: &PenningTrap::total_force_external;
|
||||||
}
|
|
||||||
else {
|
|
||||||
force = &PenningTrap::total_force_external;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Calculating the force for each particle is independent and therefore
|
||||||
|
// a good candidate for parallel execution
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
force_res[i] = (this->*force)(i);
|
force_res[i] = (this->*force)(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updating the particles is also independent, so we can parallelize
|
||||||
|
// this as well
|
||||||
#pragma omp parallel for private(p)
|
#pragma omp parallel for private(p)
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
p = &this->particles[i];
|
p = &this->particles[i];
|
||||||
@ -251,8 +263,8 @@ void PenningTrap::write_simulation_to_dir(std::string path, double time,
|
|||||||
path += '/';
|
path += '/';
|
||||||
}
|
}
|
||||||
if (mkpath(path, 0777) != 0) {
|
if (mkpath(path, 0777) != 0) {
|
||||||
std::cout << "Hello" << std::endl;
|
std::cout << "Failed to make path" << std::endl;
|
||||||
return;
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
simulation_t res
|
simulation_t res
|
||||||
@ -260,18 +272,22 @@ void PenningTrap::write_simulation_to_dir(std::string path, double time,
|
|||||||
|
|
||||||
std::ofstream ofile;
|
std::ofstream ofile;
|
||||||
|
|
||||||
|
// Writing each particle to its own file is independent and can be run in
|
||||||
|
// parallel.
|
||||||
#pragma omp parallel for private(ofile)
|
#pragma omp parallel for private(ofile)
|
||||||
for (size_t i = 0; i < this->particles.size(); i++) {
|
for (size_t i = 0; i < this->particles.size(); i++) {
|
||||||
ofile.open(path + "particle_" + std::to_string(i) + "_r.txt");
|
ofile.open(path + "particle_" + std::to_string(i) + "_r.txt");
|
||||||
for (vec_3d &vec : res.r_vecs[i]) {
|
for (vec_3d &vec : res.r_vecs[i]) {
|
||||||
ofile << vec(0) << "," << vec(1) << "," << vec(2) << "\n";
|
ofile << scientific_format(vec(0), 10, 8) << ','
|
||||||
|
<< scientific_format(vec(1), 10, 8) << ','
|
||||||
|
<< scientific_format(vec(2), 10, 8) << '\n';
|
||||||
}
|
}
|
||||||
ofile.close();
|
ofile.close();
|
||||||
ofile.open(path + "particle_" + std::to_string(i) + "_v.txt");
|
ofile.open(path + "particle_" + std::to_string(i) + "_v.txt");
|
||||||
for (vec_3d &vec : res.v_vecs[i]) {
|
for (vec_3d &vec : res.v_vecs[i]) {
|
||||||
ofile << scientific_format(vec(0), 10, 8) << ","
|
ofile << scientific_format(vec(0), 10, 8) << ','
|
||||||
<< scientific_format(vec(1), 8, 10) << ","
|
<< scientific_format(vec(1), 10, 8) << ','
|
||||||
<< scientific_format(vec(2), 8, 10) << "\n";
|
<< scientific_format(vec(2), 10, 8) << '\n';
|
||||||
}
|
}
|
||||||
ofile.close();
|
ofile.close();
|
||||||
}
|
}
|
||||||
@ -281,26 +297,33 @@ double PenningTrap::fraction_of_particles_left(double time, unsigned int steps,
|
|||||||
std::string method,
|
std::string method,
|
||||||
bool particle_interaction)
|
bool particle_interaction)
|
||||||
{
|
{
|
||||||
simulation_t res
|
double dt = time / (double)steps;
|
||||||
= this->simulate(time, steps, method, particle_interaction);
|
|
||||||
|
void (PenningTrap::*func)(double, bool);
|
||||||
|
if (method == "rk4") {
|
||||||
|
func = &PenningTrap::evolve_RK4;
|
||||||
|
}
|
||||||
|
else if (method == "euler") {
|
||||||
|
func = &PenningTrap::evolve_forward_euler;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "Not a valid method!" << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < steps; j++) {
|
||||||
|
(this->*func)(dt, particle_interaction);
|
||||||
|
}
|
||||||
|
|
||||||
int particles_left = 0;
|
int particles_left = 0;
|
||||||
|
|
||||||
for (Particle p : this->particles) {
|
// A reduction is perfect here
|
||||||
if (arma::norm(p.r_vec) < this->d) {
|
#pragma omp parallel for reduction(+:particles_left)
|
||||||
|
for (size_t i=0; i < this->particles.size(); i++) {
|
||||||
|
if (arma::norm(this->particles[i].r_vec) < this->d) {
|
||||||
particles_left++;
|
particles_left++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (double)particles_left / (double)this->particles.size();
|
return (double)particles_left / (double)this->particles.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_3d PenningTrap::get_r(int i)
|
|
||||||
{
|
|
||||||
return this->particles[i].r_vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
double PenningTrap::get_t()
|
|
||||||
{
|
|
||||||
return this->t;
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user