Program Listing for File particle.cpp¶
↰ Return to documentation for file (src/particle/particle.cpp)
#include "particle.hpp"
#include <fstream>
#include "hdf5.h"
namespace lili::particle {
const char* __LILIP_DNAME_UINT32[] = {"id", "status"};
const char* __LILIP_DNAME_DOUBLE[] = {"x", "y", "z", "u", "v", "w"};
// Constructor
Particles::Particles()
: npar_(0),
npar_max_(__LILIP_DEFAULT_BSIZE),
q_(1.0),
m_(1.0),
id_(new ulong[__LILIP_DEFAULT_BSIZE]()),
status_(new ParticleStatus[__LILIP_DEFAULT_BSIZE]()),
x_(new double[__LILIP_DEFAULT_BSIZE]()),
y_(new double[__LILIP_DEFAULT_BSIZE]()),
z_(new double[__LILIP_DEFAULT_BSIZE]()),
u_(new double[__LILIP_DEFAULT_BSIZE]()),
v_(new double[__LILIP_DEFAULT_BSIZE]()),
w_(new double[__LILIP_DEFAULT_BSIZE]()) {}
Particles::Particles(int npar)
: npar_(npar),
npar_max_(npar < __LILIP_DEFAULT_BSIZE ? __LILIP_DEFAULT_BSIZE : npar),
q_(1.0),
m_(1.0),
id_(nullptr),
status_(nullptr),
x_(nullptr),
y_(nullptr),
z_(nullptr),
u_(nullptr),
v_(nullptr),
w_(nullptr) {
id_ = new ulong[npar_max_]();
status_ = new ParticleStatus[npar_max_]();
x_ = new double[npar_max_]();
y_ = new double[npar_max_]();
z_ = new double[npar_max_]();
u_ = new double[npar_max_]();
v_ = new double[npar_max_]();
w_ = new double[npar_max_]();
// Initialize status
for (int i = 0; i < npar_; ++i) {
status_[i] = ParticleStatus::In;
}
}
Particles::Particles(int npar, int npar_max)
: npar_(npar),
npar_max_(npar_max),
q_(1.0),
m_(1.0),
id_(new ulong[npar_max]()),
status_(new ParticleStatus[npar_max]()),
x_(new double[npar_max]()),
y_(new double[npar_max]()),
z_(new double[npar_max]()),
u_(new double[npar_max]()),
v_(new double[npar_max]()),
w_(new double[npar_max]()) {
// Initialize status
for (int i = 0; i < npar_; ++i) {
status_[i] = ParticleStatus::In;
}
}
Particles::Particles(input::InputParticles input_particle)
: npar_(input_particle.n),
npar_max_(input_particle.n < __LILIP_DEFAULT_BSIZE ? __LILIP_DEFAULT_BSIZE
: input_particle.n),
q_(input_particle.q),
m_(input_particle.m),
id_(nullptr),
status_(nullptr),
x_(nullptr),
y_(nullptr),
z_(nullptr),
u_(nullptr),
v_(nullptr),
w_(nullptr) {
id_ = new ulong[npar_max_]();
status_ = new ParticleStatus[npar_max_]();
x_ = new double[npar_max_]();
y_ = new double[npar_max_]();
z_ = new double[npar_max_]();
u_ = new double[npar_max_]();
v_ = new double[npar_max_]();
w_ = new double[npar_max_]();
// Initialize status
for (int i = 0; i < npar_; ++i) {
status_[i] = ParticleStatus::In;
}
}
// Copy constructor
Particles::Particles(const Particles& other)
: npar_(other.npar_),
npar_max_(other.npar_max_),
q_(other.q_),
m_(other.m_),
id_(new ulong[other.npar_max_]()),
status_(new ParticleStatus[other.npar_max_]()),
x_(new double[other.npar_max_]()),
y_(new double[other.npar_max_]()),
z_(new double[other.npar_max_]()),
u_(new double[other.npar_max_]()),
v_(new double[other.npar_max_]()),
w_(new double[other.npar_max_]()) {
std::copy(other.id_, other.id_ + other.npar_max_, id_);
std::copy(other.status_, other.status_ + other.npar_max_, status_);
std::copy(other.x_, other.x_ + other.npar_max_, x_);
std::copy(other.y_, other.y_ + other.npar_max_, y_);
std::copy(other.z_, other.z_ + other.npar_max_, z_);
std::copy(other.u_, other.u_ + other.npar_max_, u_);
std::copy(other.v_, other.v_ + other.npar_max_, v_);
std::copy(other.w_, other.w_ + other.npar_max_, w_);
}
// Destructor
Particles::~Particles() {
delete[] id_;
delete[] status_;
delete[] x_;
delete[] y_;
delete[] z_;
delete[] u_;
delete[] v_;
delete[] w_;
}
void Particles::resize(int new_npar_max) {
ulong* new_id = new ulong[new_npar_max]();
ParticleStatus* new_status = new ParticleStatus[new_npar_max]();
double* new_x = new double[new_npar_max]();
double* new_y = new double[new_npar_max]();
double* new_z = new double[new_npar_max]();
double* new_u = new double[new_npar_max]();
double* new_v = new double[new_npar_max]();
double* new_w = new double[new_npar_max]();
std::copy(id_, id_ + npar_max_, new_id);
std::copy(status_, status_ + npar_max_, new_status);
std::copy(x_, x_ + npar_max_, new_x);
std::copy(y_, y_ + npar_max_, new_y);
std::copy(z_, z_ + npar_max_, new_z);
std::copy(u_, u_ + npar_max_, new_u);
std::copy(v_, v_ + npar_max_, new_v);
std::copy(w_, w_ + npar_max_, new_w);
delete[] id_;
delete[] status_;
delete[] x_;
delete[] y_;
delete[] z_;
delete[] u_;
delete[] v_;
delete[] w_;
id_ = new_id;
status_ = new_status;
x_ = new_x;
y_ = new_y;
z_ = new_z;
u_ = new_u;
v_ = new_v;
w_ = new_w;
npar_max_ = new_npar_max;
}
void Particles::AddID(int offset) {
for (int i = 0; i < npar_; ++i) {
id_[i] += offset;
}
}
void Particles::pswap(const int i, const int j) {
int tmp_uint32 = id_[i];
id_[i] = id_[j];
id_[j] = tmp_uint32;
ParticleStatus tmp_status = status_[i];
status_[i] = status_[j];
status_[j] = tmp_status;
double tmp_double = x_[i];
x_[i] = x_[j];
x_[j] = tmp_double;
tmp_double = y_[i];
y_[i] = y_[j];
y_[j] = tmp_double;
tmp_double = z_[i];
z_[i] = z_[j];
z_[j] = tmp_double;
tmp_double = u_[i];
u_[i] = u_[j];
u_[j] = tmp_double;
tmp_double = v_[i];
v_[i] = v_[j];
v_[j] = tmp_double;
tmp_double = w_[i];
w_[i] = w_[j];
w_[j] = tmp_double;
}
void Particles::CleanOut() {
// Keep two indices
int i = 0;
int j = npar_ - 1;
// Loop until i and j meet, swap particles if necessary
while (i < j) {
if (status_[i] == ParticleStatus::Out) {
while (status_[j] == ParticleStatus::Out) {
--j;
if (i >= j) {
break;
}
}
if (i >= j) {
break;
}
pswap(i, j);
--j;
}
++i;
}
// Check the last particle
if (status_[i] == ParticleStatus::Out) {
--i;
}
// Change the number of particles
npar_ = i + 1;
}
void SaveParticles(Particles& particles, const char* file_name) {
// Create file
hid_t file_id = H5Fcreate(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
// Create dataspace to store particles
hsize_t dims[1] = {static_cast<hsize_t>(particles.npar())};
hid_t dataspace_id = H5Screate_simple(1, dims, NULL);
// Create dataset for each integer fields
for (int i = 0; i < __LILIP_DCOUNT_ULONG; ++i) {
hid_t dataset_id =
H5Dcreate(file_id, __LILIP_DNAME_UINT32[i], H5T_NATIVE_UINT32,
dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// Write data
H5Dwrite(dataset_id, H5T_NATIVE_UINT32, H5S_ALL, H5S_ALL, H5P_DEFAULT,
particles.data_uint32(i));
// Close dataset
H5Dclose(dataset_id);
}
// Create dataset for each double fields
for (int i = 0; i < __LILIP_DCOUNT_DOUBLE; ++i) {
hid_t dataset_id =
H5Dcreate(file_id, __LILIP_DNAME_DOUBLE[i], H5T_NATIVE_DOUBLE,
dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
// Write data
H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
particles.data_double(i));
// Close dataset
H5Dclose(dataset_id);
}
// Close dataspace
H5Sclose(dataspace_id);
// Close file
H5Fclose(file_id);
}
Particles LoadParticles(const char* file_name) {
// Open file
hid_t file_id = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT);
// Get number of particles
hsize_t dims[1];
hid_t dataset_id = H5Dopen(file_id, __LILIP_DNAME_UINT32[0], H5P_DEFAULT);
hid_t dataspace_id = H5Dget_space(dataset_id);
H5Sget_simple_extent_dims(dataspace_id, dims, NULL);
int npar = dims[0];
// Create particles object
Particles particles(npar);
// Read data
for (int i = 0; i < __LILIP_DCOUNT_ULONG; ++i) {
dataset_id = H5Dopen(file_id, __LILIP_DNAME_UINT32[i], H5P_DEFAULT);
H5Dread(dataset_id, H5T_NATIVE_ULONG, H5S_ALL, H5S_ALL, H5P_DEFAULT,
particles.data_uint32(i));
H5Dclose(dataset_id);
}
for (int i = 0; i < __LILIP_DCOUNT_DOUBLE; ++i) {
dataset_id = H5Dopen(file_id, __LILIP_DNAME_DOUBLE[i], H5P_DEFAULT);
H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
particles.data_double(i));
H5Dclose(dataset_id);
}
// Close dataspace
H5Sclose(dataspace_id);
// Close file
H5Fclose(file_id);
return particles;
}
void SelectParticles(Particles& input, Particles& output, ParticleStatus status,
bool remove) {
int npar = input.npar();
// Loop over input particles
int npar_out = 0;
for (int i = 0; i < npar; ++i) {
if (input.status(i) == status) {
// Grow the output particles if necessary
if (npar_out >= output.npar_max()) {
output.resize(output.npar_max() * __LILIP_DEFAULT_GSIZE);
}
output.id(npar_out) = input.id(i);
output.status(npar_out) = input.status(i);
output.x(npar_out) = input.x(i);
output.y(npar_out) = input.y(i);
output.z(npar_out) = input.z(i);
output.u(npar_out) = input.u(i);
output.v(npar_out) = input.v(i);
output.w(npar_out) = input.w(i);
++npar_out;
if (remove) {
input.status(i) = ParticleStatus::Out;
}
}
}
// Change the number of particles in output
output.npar() = npar_out;
// Clean up input particles
if (remove) {
input.CleanOut();
}
}
void LabelBoundaryParticles(Particles& particles, mesh::MeshSize mesh_size) {
// Get the range of each dimension
const double xmin = mesh_size.x0;
const double xmax = mesh_size.x0 + mesh_size.lx;
const double ymin = mesh_size.y0;
const double ymax = mesh_size.y0 + mesh_size.ly;
const double zmin = mesh_size.z0;
const double zmax = mesh_size.z0 + mesh_size.lz;
double* __restrict__ x = particles.x();
double* __restrict__ y = particles.y();
double* __restrict__ z = particles.z();
ParticleStatus* __restrict__ status = particles.status();
// Loop over particles and label them
// TODO: Can probably improve this branching logic
for (int i = 0; i < particles.npar(); ++i) {
if (status[i] == ParticleStatus::Tracked) {
if (x[i] < xmin) {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX0Y0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX0Y0Z1;
} else {
status[i] = ParticleStatus::TX0Y0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX0Y1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX0Y1Z1;
} else {
status[i] = ParticleStatus::TX0Y1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX0Z1;
} else {
status[i] = ParticleStatus::TX0;
}
}
} else if (x[i] > xmax) {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX1Y0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX1Y0Z1;
} else {
status[i] = ParticleStatus::TX1Y0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX1Y1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX1Y1Z1;
} else {
status[i] = ParticleStatus::TX1Y1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::TX1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TX1Z1;
} else {
status[i] = ParticleStatus::TX1;
}
}
} else {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TY0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TY0Z1;
} else {
status[i] = ParticleStatus::TY0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::TY1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TY1Z1;
} else {
status[i] = ParticleStatus::TY1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::TZ0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::TZ1;
}
}
}
} else {
if (x[i] < xmin) {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::X0Y0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X0Y0Z1;
} else {
status[i] = ParticleStatus::X0Y0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::X0Y1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X0Y1Z1;
} else {
status[i] = ParticleStatus::X0Y1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::X0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X0Z1;
} else {
status[i] = ParticleStatus::X0;
}
}
} else if (x[i] > xmax) {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::X1Y0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X1Y0Z1;
} else {
status[i] = ParticleStatus::X1Y0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::X1Y1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X1Y1Z1;
} else {
status[i] = ParticleStatus::X1Y1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::X1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::X1Z1;
} else {
status[i] = ParticleStatus::X1;
}
}
} else {
if (y[i] < ymin) {
if (z[i] < zmin) {
status[i] = ParticleStatus::Y0Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::Y0Z1;
} else {
status[i] = ParticleStatus::Y0;
}
} else if (y[i] > ymax) {
if (z[i] < zmin) {
status[i] = ParticleStatus::Y1Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::Y1Z1;
} else {
status[i] = ParticleStatus::Y1;
}
} else {
if (z[i] < zmin) {
status[i] = ParticleStatus::Z0;
} else if (z[i] > zmax) {
status[i] = ParticleStatus::Z1;
}
}
}
}
}
}
void PeriodicBoundaryParticles(Particles& particles, mesh::MeshSize mesh_size) {
// Get the range of each dimension
const double lx = mesh_size.lx;
const double ly = mesh_size.ly;
const double lz = mesh_size.lz;
const double xmin = mesh_size.x0;
const double xmax = mesh_size.x0 + lx;
const double ymin = mesh_size.y0;
const double ymax = mesh_size.y0 + ly;
const double zmin = mesh_size.z0;
const double zmax = mesh_size.z0 + lz;
double* __restrict__ x = particles.x();
double* __restrict__ y = particles.y();
double* __restrict__ z = particles.z();
// Loop over particles and move them
for (int i = 0; i < particles.npar(); ++i) {
if (x[i] < xmin) {
x[i] += lx;
} else if (x[i] > xmax) {
x[i] -= lx;
}
if (y[i] < ymin) {
y[i] += ly;
} else if (y[i] > ymax) {
y[i] -= ly;
}
if (z[i] < zmin) {
z[i] += lz;
} else if (z[i] > zmax) {
z[i] -= lz;
}
}
}
} // namespace lili::particle